ベース
文字列はプログラミングで最も一般的に使用されるデータ構造であり、文字列を操作する必要がある場所はほとんどどこでもあります。たとえば、文字列が正当なメールアドレスかどうかを判断する場合、@
前後の部分文字列をプログラム的に抽出して単語かドメイン名かを判断することはできますが、これは面倒なだけでなく、再利用することも困難です。コード。
正規表現は、文字列を照合するための強力な武器です。その設計思想は、記述言語を使用して文字列のルールを定義することです。ルールに準拠する文字列はすべて「一致」とみなされます。それ以外の場合、文字列は不正です。
したがって、文字列が合法的な電子メールであるかどうかを判断する方法は次のとおりです。
- 電子メールに一致する正規表現を作成します。
- この正規表現を使用してユーザーの入力を照合し、それが合法かどうかを判断します。
正規表現は文字列でも表されるため、まず文字を使用して文字を記述する方法を理解する必要があります。
正規表現では、文字を直接指定すると完全一致となります。
use は\d
数値と一致することも、 use は\w
文字または数字と一致することも、.
任意の文字と一致することもできます。
-
'00\d'
一致させることはできます'007'
が、一致させることはできません'00A'
。 -
'\d\d\d'
一致する可能性があります'010'
。 -
'\w\w\d'
一致する可能性があります'py3'
。 -
'py.'
'pyc'
、'pyo'
など'py!'
と一致します。
正規表現で可変長文字を照合するには、use は*
任意の数の文字 (0 を含む) を意味し、+
少なくとも 1 つの文字を意味し、?
0 または 1 文字を意味し、{n}
n 文字を意味し、{n,m}
nm 文字を意味します。
複雑な例を見てみましょう\d{3}\s+\d{3,8}
。
左から右に読んでみましょう:
\d{3}
3 つの数字が一致することを示します。たとえば'010'
、 ;\s
スペース (タブやその他の空白文字を含む) と一致するため、一致するなど、\s+
少なくとも 1 つのスペースがあることを意味します。' '
' '
\d{3,8}
3 ~ 8 の数値を表します (例: )'1234567'
。
まとめると、上記の正規表現は、任意の数のスペースで区切られた市外局番を持つ電話番号を照合できます。
'010-12345'
このような数値を照合したい場合はどうすればよいでしょうか? 特殊文字であるため'-'
、正規表現でエスケープする必要がある'\'
ため、上記の正規表現は です\d{3}\-\d{3,8}
。
'010 - 12345'
しかし、スペースがあるためまだ一致しません。したがって、より複雑なマッチング方法が必要になります。
高度な
より正確に一致させるには、次のように範囲表現を使用できます。[]
[0-9a-zA-Z\_]
数字、文字、またはアンダースコアと一致します。[0-9a-zA-Z\_]+
'a100'
、'0_Z'
など、少なくとも 1 つの数字、文字、またはアンダースコアで構成される文字列と一致します'Py3000'
。[a-zA-Z\_][0-9a-zA-Z\_]*
文字またはアンダースコアで始まり、その後に任意の数の数字、文字、またはアンダースコアが続く任意の文字列と一致します。これは Python の有効な変数です。[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}
より正確には、変数の長さは 1 ~ 20 文字 (前に 1 文字 + 後ろに最大 19 文字) に制限されます。
A|B
A または B と一致するため、または のいずれか(P|p)ython
と一致します。'Python'
'python'
^
行の先頭を示し、^\d
数字で始める必要があることを示します。
$
行の終わりを示し、\d$
数字で終わる必要があることを示します。
お気づきかもしれませんが、 とpy
一致させることもできます'python'
が、^py$
これを追加すると行全体と一致することになり、 とのみ一致します'py'
。
再モジュール
準備知識があれば、Python で正規表現を使用できます。Python は、re
すべての正規表現機能を含むモジュールを提供します。Python の文字列自体も\
エスケープを使用するため、次の点に特別な注意を払う必要があります。
s = 'ABC\\-001' # Python的字符串
# 对应的正则表达式字符串变成:
# 'ABC\-001'
したがって、r
エスケープを心配する必要がないように、Python プレフィックスを使用することを強くお勧めします。
s = r'ABC\-001' # Python的字符串
# 对应的正则表达式字符串不变:
# 'ABC\-001'
まず、正規表現が一致するかどうかを判断する方法を見てみましょう。
>>> import re
>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345') # 注意,{3,8}的8之前不能有空格
<re.Match object; span=(0, 9), match='010-12345'>
>>> re.match(r'^\d{3}\-\d{3,8}$', '010 12345')
>>>
match()
このメソッドは一致があるかどうかを判断し、一致した場合はオブジェクトを返しMatch
、そうでない場合は を返しますNone
。一般的な判断方法は次のとおりです。
test = '用户输入的字符串'
if re.match(r'正则表达式', test):
print('ok')
else:
print('failed')
# 结果:failed
文字列を分割する
正規表現を使用して文字列を分割すると、固定文字を使用するよりも柔軟になります。通常の分割コードを参照してください。
>>> 'a b c'.split(' ')
['a', 'b', '', '', 'c']
連続したスペースは認識できないため、正規表現を使用してみてください。
>>> re.split(r'\s+', 'a b c') # \s+表示至少有1个空格
['a', 'b', 'c']
スペースがいくつあっても正常に分割できます。参加してみてください,
:
>>> re.split(r'[\s\,]+', 'a, b,c d') # 使用[]更精确地表示范围
['a', 'b', 'c', 'd']
もう一度追加してみてください;
:
>>> re.split(r'[\s\,\;]+', 'a,b;; c d')
['a', 'b', 'c', 'd']
ユーザーが一連のタグを入力した場合は、次回からは正規表現を使用して不規則な入力を正しい配列に変換することを忘れないでください。
グループ
正規表現には、単純に一致があるかどうかを判断するだけでなく、部分文字列を抽出する強力な機能もあります。で表されるのは()
抽出対象のグループ(Group)です。例えば:
^(\d{3})-(\d{3,8})$
2 つのグループがそれぞれ定義されており、市外局番と市内番号は一致する文字列から直接抽出できます。
>>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
>>> m
<re.Match object; span=(0, 9), match='010-12345'>
>>> m.group(0)
'010-12345'
>>> m.group(1)
'010'
>>> m.group(2)
'12345'
正規表現でグループが定義されている場合は、Match
オブジェクトのメソッドを使用してgroup()
部分文字列を抽出できます。
group(0)
これは常に正規表現全体に一致する文字列であることに注意してください。group(1)
、 、group(2)
... は 1 番目、2 番目、... の部分文字列を表します。
部分文字列を抽出するのに非常に便利です。もっと残酷な例を見てみましょう:
>>> t = '19:05:30'
>>> m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t) # |表示或者的意思
>>> m.groups()
('19', '05', '30')
この正規表現により、法定時刻を直接識別できます。ただし、日付の識別など、正規表現を使用して完全な検証を達成できない場合があります。
'^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$'
'2-30'
このような不正な日付については'4-31'
、依然として正規表現による識別が不可能であるか、書き出すことが非常に困難であるため、現時点では識別に連携するプログラムが必要となる。
貪欲なマッチング
最後に、通常のマッチングはデフォルトでは貪欲マッチング、つまり可能な限り多くの文字をマッチングすることを意味することに注意してください。たとえば、次の数字と一致します0
。
>>> re.match(r'^(\d+)(0*)$', '102300').groups() # *表示任意个字符(包括0个)
('102300', '')
貪欲一致により\d+
、以下のすべてが直接0
一致し、結果は0*
空の文字列のみと一致します。
\d+
次のものと0
一致するには、非貪欲マッチングを使用する必要があります(つまり、できるだけ少ない一致) 。1 つを追加すると、非貪欲マッチングを使用できるよう?
になります\d+
。
>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')
コンパイル
Python で正規表現を使用する場合、re モジュールは内部で 2 つのことを行います。
- 正規表現をコンパイルします。正規表現の文字列自体が不正な場合は、エラーが報告されます。
- コンパイルされた正規表現を使用して文字列を照合します。
正規表現を何千回も再利用する場合は、効率を高めるために、正規表現をプリコンパイルできます。再利用する場合、このコンパイルの手順は必要ありません。次のように直接一致します。
>>> import re
# 编译:
>>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
# 使用:
>>> re_telephone.match('010-12345').groups()
('010', '12345')
>>> re_telephone.match('010-8086').groups()
('010', '8086')
コンパイル後、正規表現オブジェクトが生成されますが、オブジェクト自体に正規表現が含まれているため、対応するメソッドを呼び出すときに正規文字列を指定する必要はありません。
まとめ
正規表現は非常に強力であるため、1 つのセクションだけですべてをカバーすることは不可能です。正規ルールの内容を全てわかりやすく解説すると、分厚い本が1冊書けるほどです。正規表現に関する問題が頻繁に発生する場合は、正規表現のリファレンス ブックが必要になる場合があります。
練習する
1. 電子メール アドレスを検証するための正規表現を作成してみてください。バージョン 1 では、同様の電子メールを検証できるはずです。
-
誰か@gmail.com
import re
def is_valid_email(addr):
re_email = re.compile(r'^[a-zA-Z\.]+@[0-9a-zA-Z]+\.com$')
# 另一种写法:
# re_email = re.compile(r'^[\w]+\.?[\w]+@[\w]+\.com$')
# 正则解释: 字母一个以上 .一个或没有 字母一个以上 @ 字母不限 .com
if re_email.match(addr):
return True
# 测试:
assert is_valid_email('[email protected]')
assert is_valid_email('[email protected]')
assert not is_valid_email('bob#example.com')
assert not is_valid_email('[email protected]')
print('ok')
# 结果:ok
2. バージョン 2 では、次の名前の電子メール アドレスを抽出できます。
- [email protected] => トム・パリス
- [email protected] => ボブ
import re
def name_of_email(addr):
re_email = re.compile(r'^<?([\w\s]+)>?\s*[\w]*@[\w]+\.(org|com)$')
# 正则解释:<0或1个 字母、空格一个以上 >0或1个 空格不限 字母不限@字母一个以上 . org或者com
if re_email.match(addr):
return re_email.match(addr).group(1)
# 测试:
assert name_of_email('<Tom Paris> [email protected]') == 'Tom Paris'
assert name_of_email('[email protected]') == 'tom'
assert name_of_email('[email protected]') == 'bob'
print('ok')
# 结果:ok