2009/02/16

Sukio Sukio Sukio Python - VIII

リアクション: 
第8回目は、正規表現に行きたいと思います。
正規表現は、とても難しいですので、ワタクシも全て理解しているとは言いがたいです。
ですが、少しでも学ぶことが出来れば、強力なツールになること間違いなしです。
正規表現は、パターンマッチをするには、最強です。
では、そのほんのちょっとしたさわりをご紹介します。

例えば、duplicateなどした場合には、cube1など、お尻に数字が入ります。
さらに100個くらい増やした後、幾つかのcubeをABCやguideなどと数字は生かしたままりネームしてしまったとします。
最悪な事に、幾つかのオブジェクトはDeleteしてあります。
その後、そのオブジェクト達の番号に対応するnullを用意しなくてはならない場合があるとします。
さらに、nullをリグとするposeコンストをしたいです。
cubeとABCとguideは、番号続きであるもののごちゃ混ぜ。
さらにnullには、その番号に対応した数字を入れなくてはなりません。

cube1
guide3
ABC24
cube54
guide98
ABC145
cube203
...

数字を取得するのなら、cubeやABCやguideを抜いたら良いですね。
ですが、この場合の発想は逆で、数字だけを抜き取ります。
こういったときには、正規表現を使うのが一番です。

まず、正規表現を使うことが出来るreモジュールをインポートします。

import re

これで、reモジュールを使うことが出来ます。
reには幾つかのメソッドが存在します。
まずは、compile
パターンオブジェクトを作成します。

reD = re.compile(r'\d+$')

\d+

ここで使われている特殊な文字『\d』は数字を意味します。
digitのdですね。
+を付けると、0や567など1以上の複数にマッチします。

$

これは、末尾を意味します。

\d+$

としておけば、末尾が数字のものという意味になります。
次にパターンにひっかかるかどうかのマッチオブジェクトを作成します。
ここでsearchを使います。

m = reD.search('cube54')

mにマッチオブジェクトが入りました。
そして、実際にマッチングしている文字列を取り出すには

m.group()

とします。
これで

54

が取得出来ます。
選択して、それに対応するnullを作成しposeコンストするにはこんな感じにします。



これにより、数字に対応したnullがposeコンスト付きで出来ることでしょう。

もう少し複雑にしましょう。
例えば、カメラモデル名にシーン番号カット番号イン点アウト点などを表記させておきます。

s021c156_Camera_231_310

このパターンは、かなりの数に上ります。
通常の考え方で、カット番号を取得したい場合は
カメラのモデルをoCamMdlとした場合

oCamMdl.Name[5:8]

とすれば『156』を取得出来ます。
しかし、こうなればどうでしょう?

s1c56_Camera_231_310

『_Ca』が取得されてしまいます。
これではあまりに情けないので、正規表現を使って取得してみることにしましょう。

パターンオブジェクトを作成します。

reCam = re.compile(r'(s)(\d+)(c)(\d+)(_Camera_)(\d+)(_)(\d+)')

()を付けるとくくられて、グルーピングされます。これは、後述します。
上記を日本語で書くとこんな感じでしょうか。

(sにマッチ)(数字にマッチ,+で複数も可)(cにマッチ)(数字にマッチ,+で複数も可)(_Camera_にマッチ)(数字にマッチ,+で複数も

可)(_にマッチ)(数字にマッチ,+で複数も可)

次に、パターンオブジェクトに対して、実際に判定する文字列を入れマッチオブジェクトを作成してみます。

reCam = re.compile(r'(s)(\d+)(c)(\d+)(_Camera_)(\d+)(_)(\d+)')
m = reCam.search('s021c156_Camera_231_310')

mにマッチオブジェクトが入りました。
そして、実際にマッチングしている文字列を取り出すには

m.group()

とします。
これで

s021c156_Camera_231_310

が取得出来ます。
ここまではあまり意味無いですが今度は

'Camera_root'

を入れてみます。

m = reCam.search('Camera_root')
m.group()

これはエラーになってしまいます。
パターンにひっかから無かったからです。
searchで、パターンにマッチ出来ないと、Noneオブジェクトが返ってくる仕組みになっています。
ですので

if m:
m.group()

などとすれば、マッチしているかどうか判定出来ます。
ifで、Noneは、Falseと判定されます。
次に、マッチオブジェクトに対して、groups()としてみましょう。

import re
app = Application
log = app.LogMessage
reCam = re.compile(r'(s)(\d+)(c)(\d+)(_Camera_)(\d+)(_)(\d+)')
m = reCam.search('s021c156_Camera_231_310')
if m:
 log(m.groups())


結果は、()でくくったグルーピングをタプルとして返します。

('s', '021', 'c', '156', '_Camera_', '231', '_', '310')

カット番号を取りたい場合は決まって4番目の値をとりたいので

m.group(4)

とすれば、目的のカット番号

156

が取得出来ますね。

ここでもう少し便利にすることが出来ます。
パターンに名前を付けることが出来たりもします。

import re
app = Application
log = app.LogMessage
reCam = re.compile(r'(s)(?P<scn>\d+)(c)(?P<cut>\d+)(_Camera_)(?P<in>\d+)(_)(?P<out>\d+)')
m = reCam.search('s021c156_Camera_231_310')
if m:
 log(m.group('scn'))
 log(m.group('cut'))
 log(m.group('in'))
 log(m.group('out'))
このように

(?P<scn>\d+)

とすればscnという名前から取得出来るようにタグを付けておいて、後で呼び出すときに指定できるようにすることも可能です。

このように、正規表現は1冊の本として出ることが許されるほど複雑怪奇です。
ですが、webには、沢山の例がありますので、少しずつ覚えて行けばOKです。
使えなくても対した問題にはなりませんが、使えるようになれば、更なる進歩が望めます。

次回ももう少し正規表現の世界にダイブしてみることにしましょう。
では、しばらくの沈黙の後に。

0 件のコメント: