coLinux日記

coLinuxはフリーソフトを種として、よろずのシステムとぞなれりける。

SimplePrograms で Python を学ぶ その06

2024-04-05 16:08:07 | Python
SimplePrograms - Python Wiki
https://wiki.python.org/moin/SimplePrograms

の 6番目のプログラムは、import と正規表現です。
(以下で、¥と表示されている場合は、バックスラッシュです。)

import re
for test_string in ['555-1212', 'ILL-EGAL']:
   if re.match(r'^\d{3}-\d{4}$', test_string):
      print (test_string, 'is a valid US local phone number')
   else:
      print (test_string, 'rejected')


1行目の import ですが、

「ある 1 つの module にある Python コードから他のモジュールを インポート することで、そこにあるコードへアクセスできるようになります。 import 文はインポート機構を動かす最も一般的な方法ですが、それが唯一の方法ではありません。」

import文で、re というモジュールをインポート(つまり、使えるように)することですね。
これで、3行目の re.match() が使えるようになるという、他のオブジェクト指向の言語で良くある形式ですね。

次に、
https://docs.python.org/ja/3/library/re.html
から Python の正規表現の意味を調べてみます。

まずは、このプログラムの実行結果です。(例によって、インデントがある前提でご覧下さい。)

>>> import re
>>> for test_string in ['555-1212', 'ILL-EGAL']:
... if re.match(r'^\d{3}-\d{4}$', test_string):
... print (test_string, 'is a valid US local phone number')
... else:
... print (test_string, 'rejected')
...
555-1212 is a valid US local phone number
ILL-EGAL rejected
>>>

注目するのは、print()で、カンマで区切った複数の引数を与えると、連続して表示されると言うことです。
確かめて見ましょう。引数が一つの場合は今まで通りの表示です。

>>> print(test_string)
ILL-EGAL

これが2つの引数になると、1文字の空白を挟んで表示されることが確認できます。
>>> print('aaa', 'bbb')
aaa bbb
>>>

さて、for で、2要素のリストを定義して先頭の要素から順番に test_string に値を代入して 2回ループするのが分かります。
ループする中身ですが、if 文が出てきました。形式は以下の様になると思います。

if じょうけん:
条件を満たした場合の処理(インデントする)
else:
条件を満たさない場合の処理(インデントする)

恐らく他のプログラム言語のように、条件のブール値が真(True)なら最初の処理を、偽(False)ならelse:の後を処理する、となるのでしょう。条件の形式(条件式?)は多くのプログラミング言語と一緒と推定して試してみましょう。
>>> a = 'abc'
>>> if a == 'abc':
...     print('Yes')
... else:
...     print('No')
...
Yes

>>> if a != 'abc':
...     print('Yes')
... else:
...     print('No')
...
No
>>>
間違いなさそうですね。

Pythonではインデントが重要なので、「 if 条件: 」 と 「 else: 」のインデントが揃っている必要がありそうです。
ここで、else: のインデントをずらしてみましょう。
>>> if a != 'abc':
...     print('Yes')
...   else:
File "<stdin>", line 3
else:
^
IndentationError: unindent does not match any outer indentation level
>>>
やはり、エラーになりました。インデントが揃っているかどうかで、if と else の対を決定しているようです。

プログラムに戻って、3行目のif文の条件を見てみましょう。

re.match(r'^\d{3}-\d{4}$', test_string)

re のメソッドの match を使っています。つまり、reモジュールが含む match()関数みたいなものですね。
1番目の引数の正規表現と2番目の引数の値が一致したら条件を満たす(真)となるものも一般的です。

正規表現と言えば、grep 、 awk、 sed コマンドなどで使われますが、

「{n}」 は、直前の1文字がちょうどn個の並び
「^」 は、直後の正規表現が文字列の先頭であることを示す
「$」 は、直前の正規表現が文字列の末尾であることを示す

は、一般的な解釈で問題ないですね。

Pythonの正規表現では、

\d は、特殊シーケンスであり、

「Unicode (str) パターンでは:
任意の Unicode 10 進数字 (Unicode 文字カテゴリ [Nd]) にマッチします。これは [0-9]
とその他多数の数字を含みます。 ASCII フラグが使われているなら [0-9] のみにマッチします。
8 ビット (bytes) パターンでは:
任意の 10 進数字にマッチします。これは [0-9] と等価です。」


とのことですから、ここは 8 ビットパターンなので、\d{3} は0~9の数字3文字を示し、\d{4} は0~9の数値4文字を示すようです。

と言うことで、'^\d{3}-\d{4}$' は、「3文字の数字-4文字の数字」となる8文字の文字列と一致するものを表すようです。

残りのその前の'r'文字は何でしょう。

これは、正規表現の

「バックスラッシュの使い方は、 Python の文字列リテラルにおける同じ文字の使い方と衝突します。」 

なので必要で、

「これを解決するには、正規表現パターンに Python の raw 文字列記法を使います。 'r' を前置した文字列リテラル内ではバックスラッシュが特別扱いされません。」

だそうです。つまり、バックスラッシュ「\」を分かりやすく使うために 「r」 が必要だということですね。

正規表現でバックスラッシュを使うなら r を頭に付けると覚えておけば良さそうです。

念のため、re.match() の出力を調べて見ましょう。4文字の数字かどうか、の例です。

>>> a='1234'
>>> b='567'
>>> import re
>>> c=re.match(r'^\d{4}$',a)
>>> d=re.match(r'^\d{4}$',b)
>>>
>>> print(c)
<_sre.SRE_Match object; span=(0, 4), match='1234'>
>>> print(d)
None
>>>

if 文は、「None」で無ければ条件を満たすとなるようです。
正規表現にマッチした場合に返されるものを 「マッチオブジェクト」 と言うそうです。

「マッチオブジェクトのブール値は常に True です。」

なので、if文の条件に使えるようです。つまり、

>>> if c:
... print('TRUE')
...
TRUE
>>> if d:
... print('TRUE')
...
>>>

となるわけです。マッチオブジェクトの使い方は、今後さらに分かるかもしれません。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする