Python学習-正規表現

文字列はプログラミングで最も頻繁に関与するデータ構造であり、文字列を操作する必要性はほとんどどこにでもあります。たとえば、文字列が正当な電子メールアドレスであるかどうかを判断するには、@の前後の部分文字列をプログラムで抽出して、それが単語とドメイン名であるかどうかを判断することは可能ですが、これは面倒なだけでなく、面倒でもあります。コードを再利用するのは難しい

正規表現は、文字列を照合するための強力な武器です。彼の設計思想は、記述言語を使用して文字列のルールを定義することです。ルールに準拠する文字列はすべて「一致」すると見なされます。それ以外の場合、文字列は不正です。

したがって、文字列が有効な電子メールであるかどうかを判断する方法は次のとおりです。

  1. 電子メールに一致する正規表現を作成します。
  2. 正規表現を使用してユーザーの入力と一致させ、それが正当かどうかを判断します。

正規表現も文字列で表されるため、最初に文字を使用して文字を記述する方法を理解する必要があります。

正規表現では、文字を直接指定すると完全一致になります。数字に一致させるには\ dを使用し、文字または数字に一致させるには\ wを使用します。

  • '00 \ d 'は' 007 'と一致できますが、' 00A 'と一致できません。
  • '\ d \ d \ d'は '010'と一致できます。
  • '\ w \ w \ d'は 'py3'と一致できます。

。任意の文字列に一致できるため、次のようになります。

  • 「py。」は「pyc」、「pyo」、「py!」などと一致します。

可変長文字を照合するには、正規表現で*を使用して任意の数の文字(0を含む)を示し、+を使用して少なくとも1文字を示し、?を使用します。0または1文字を表し、{n}はn文字を表し、{n、m}はnm文字を表し
ます。複雑な例を見てみましょう:\ d {3} \ s + \ d {3,8}。
s:スペース

左から右に読んでみましょう:

  1. \ d {3}は、「010」などの3桁の一致を意味します。
  2. \ sはスペース(Tabなどの空白文字も含む)と一致する可能性があるため、\ s +は、''、 ''などの一致など、少なくとも1つのスペースがあることを意味します。
  3. \ d {3,8}は、「1234567」などの3〜8個の数字を意味します。

まとめると、上記の正規表現は、電話番号を任意の数のスペースで区切られた市外局番と一致させることができます。

'010-12345'のような番号に一致させたい場合はどうなりますか?'-'は特殊文字であるため、正規表現では ''でエスケープする必要があります。したがって、上記の正規表現は\ d3- \ d {3,8}です。
ただし、スペースが含まれているため、「010-12345」とは一致しません。そのため、より複雑な一致方法が必要です。

高度な

より正確に一致させるには、[]を使用して範囲を示します。次に例を示します。

  • [0-9a-zA-z_]は数字、文字、またはアンダースコアに一致させることができます。
  • [0-9a-zA-z _] +は、「a100」、「0_z」、「Py3000」など、少なくとも1つの数字、文字、またはアンダースコアで構成される文字列と一致します。(+記号を使用すると、順序は自由に変更できます)(+は少なくとも1つを意味します)
  • [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'

したがって、エスケープするのではなく、Pyhonのrプレフィックスを使用することを強くお勧めします。

s = r'ABC\-001'
# 对应的正则表达式字符串不变:
# 'ABC\-001'

まず、正規表現が一致するかどうかを判断する方法を見てください。

>>>import re
>>>re.match(r'^\d{3}\-\d{3,8}$','010-12345')
><_sre.SRE_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')

分割文字列

正規表現を使用して文字列を分割する方が、固定文字を使用するよりも柔軟性があります。通常の分割コードを参照してください。

>>> 'a b   c'.split(' ')
['a', 'b', '', '', 'c']

連続したスペースは認識できません。正規表現を使用してみてください。

>>> re.split(r'\s+', 'a b   c')
['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']

ユーザーがタグのセットを入力した場合は、次回、正規表現を使用して不規則な入力を正しい配列に変換することを忘れないでください。

グループ化

正規表現には単に一致するかどうかを判断するだけでなく、部分文字列抽出する強力な機能もあります。()を使用して、抽出するグループを示します。次に例を示します。
^(\ d {3})-(\ d {3,8})$はそれぞれ2つのグループを定義し、市外局番と市内番号は一致した文字列から直接抽出できます。

>>>m = re.match(r'^(\d{3})-(\d{3,8})$','010-12345')
>>>m
<_sre.SRE_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 [0-9]について考えないでください:0と、
正規表現の0 [0-9]以外の任意の数が突然表示されます文字または数字はそれ自体を表す場合があります。

この正規表現は、法定時間を直接識別できます。ただし、日付の識別など正規表現を使用して検証を完了できない場合があります。

'^(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()
>('102300', '')

\ d +は貪欲なマッチングを使用するため、背後にあるすべての0に直接一致します。その結果、0 *は空の文字列にのみ一致します。

次の0に一致させるには、\ d +に貪欲でない一致を使用させる(つまり一致をできるだけ少なくする)必要があります。\ d +に貪欲でないマッチングを使用させることができます。

>>>re.match(r'^(\d+?)(0*)$','102300').groups()
>('1023', '00')

コンパイル

Pythonで正規表現を使用する場合、reモジュールは内部で2つのことを行います。

  1. 正規表現をコンパイルします。正規表現自体の文字列が不正な場合、エラーが報告されます。
  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は、同様の電子メールを検証できるはずです。

考え方
はとてもシンプルでシンプルです。重要なのは
、2つのメールを前面のみで分解し、背面で同じものを分解することです。
次に、^ ...忘れてください。単純すぎて、時間を無駄にすることはありません。

若すぎる、心はまだ変わっていません。

import re
def is_valid_email(addr):
        return re.match(r'^([\w]+?)(\.{0}|\.)(\w+@\w+\.com)$', addr)

if __name__=="__main__":
	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')

変更後

def is_valid_email(addr):
    # (\.{0}|\.)没必要,直接放到前面去
    # ([\w]+?)(\.{0}|\.)合并成[\w\.]+
    # 表示匹配至少一个字母或下划线或.
    # @ 和 . 没必要在分组里,所以写在了分组外面
    # []表示范围,不一定是数字范围,也可以是你选定的访问
    # [\w\.]这个就是一个范围
    return re.match(r'^([\w\.]+)@(\w+)\.(\w+)$', addr)

バージョン2では、次の名前の電子メールアドレスを抽出できます。

[email protected]=>
トムパリス[email protected]=> bob

import re


def is_valid_email(addr):
    # 切记,看情况加^和$符号啊!!
    # 加了就是从开头开始了,那么findall和search就没意义了。
    matchObj = re.compile(r'()([\w]+)(@\w+\.[\w]+)')
    print(matchObj.search(addr).groups())
    return matchObj.search(addr)


if __name__ == '__main__':
    assert is_valid_email('<Tom Paris> [email protected]')
    print('ok')

気が変わった後

    nameMatch = re.compile(r'<?([\w\s]+)>? ([\w]+)@([\w]+).([\w]+)$')

([\ w \ s] +)と([\ w] +)に一致し、角かっこの前にスペースがあるため、これはまだ機能しません。
だからそれを変更する必要があります

import re


def name_of_email(addr):
	nameMatch = re.compile(r'<?([\w\s]+)>?([\w\s]*)@([\w]+).([\w]+)$')
	return nameMatch.match(addr).group(1)

if __name__ == '__main__':
    assert name_of_email('<Tom Paris> [email protected]') == 'Tom Paris'
    assert name_of_email('[email protected]') == 'tom'
    print('ok')
<Tom Paris> tom@voyager.org => Tom Paris
bob@example.com => bob

分析:

  1. この<および>は使用される場合と使用されない場合がありますか?
  2. トムパリスには文字とスペースがあるので、範囲を設定します[\ w \ s] +
  3. ただし、2番目のステップはすでに文字またはスペースと一致しています。次のボブの場合、最初のステップまたは2つで一致するコンテンツがないことがわかりますが、別のタムがあるため、後者のみを設定できます。 to [\ w \ s] *、このアスタリスクは任意の数に一致することを意味します。
  4. @グループに入れないで、外に書いて
  5. ([\ w] +)
  6. 。([\ w] +)$

おすすめ

転載: blog.csdn.net/qq_44787943/article/details/112597076