詳細Pythonの正規表現モジュール(7)

グイド・ヴァンロッサム(グイド・ヴァンロッサム)のPythonの創設者。クリスマス1989の間に、アムステルダムのグイド・ヴァンロッサム時間を渡すためには、ABCなどの言語を新しいスクリプトインタプリタの開発を決定しました継承.Pythonの一つは、純粋なフリーソフトウェアで、ソースコードやインタプリタは、Python :. Pythonの提唱者のGPL(GNU一般公衆利用許諾契約書)プロトコル哲学従っCPythonと:、「エレガント」「クリア」、「シンプル」を、Pythonはありますこの問題を解決するための最も単純で最もエレガントで最も明白な方法。

また、正規表現として知られている正規表現(Regluar式)は、この概念は、もともとUnixツールによって開発されました(などのsedとgrep)人気、多くの場合、コード内でRESと略す正規表現は、それが本質的に小さいです、専門性の高いプログラミング言語、正式の文字列操作でサポートされている多くのプログラミング言語、人気の高い用語、n個の方法を一緒に説明の文字または文字列に特別な意味と組み合わせて使用​​されるシンボルの数は、モジュールですPythonで包埋し、モジュールを再によって実装、正規表現パターンは、Cで書かれ、次いで、マッチングエンジンによって実行される、バイトコードの系列にコンパイルされます。

正規表現は、メインアプリケーションオブジェクトのテキストは、その最も基本的な機能は、テキストを一致させることです、そしてテキストは文字の数で構成されているので、正規表現のマッチングが実際に正規表現文字の文字である普通字符元字符正規表現は、これらの通常の文字と特殊なメタキャラクタであるが、特定の正規表現マッチングを表すために、このルールにマッチする、検索、置換、またはそれらの指定された規則に沿ったテキストをカット組み合わせ。

ユニバーサル文字が一致

文法 解決するには、ワイルドカードのマッチングアクション
他のデフォルトの一致\nフラグを指定した場合、任意の1つの文字よりは、=改行を含め、すべての文字に一致DOTALL
\ 表意文字オフ、つまり、通常は本来の意味を変更する文字を作った後、文字をエスケープ
[X..y] 文字セット(文字ベース)、このパラメータは文字範囲のルックアップを指定するために使用されます
\ A *あなたが使用している場合にのみ、最初から文字に一致するre.search("\Aabc","alexabc")結果が一致しません
\ Z 文字だけの終わりに一致する文字列をして、指定されたデータの末尾にマッチ$同じ参照番号の効果
\ dは 試合数、範囲[0-9]、0-9に一致する任意の数の
\ D 非マッチング数、範囲[^\d]デジタルに加えて、他の文字に一致します、
\ワット 数字や文字をマッチング、マッチング範囲[A-Za-z0-9]
\ W 非マッチング文字や数字、非マッチングの範囲[A-Za-z0-9]
S なマッチとして空白文字、マッチングre.search("\s+","ab\tc1\n3").group()結果を'\t'

定期的な記号(.):ドットは文字を表し、改行文字以外の任意のものと一致。

>>> import re

>>> re.search("he.o","helo hello helllo hellllo").group()
'helo'
>>> re.search("he...o","helo hello helllo hellllo").group()
'helllo'
>>> re.findall("he.o","helo heao hello helllo hellllo")
['helo', 'heao']

定期的な記号は(\):データを照合するときは、使用されるエスケープ、エスケープ文字を使用する必要があります。

>>> re.search("..\\t","hello\t lyshark\n").group()
'lo\t'
>>> re.search("\\t","hello\t lyshark\n").group()
'\t'
>>> re.search("\t","hello\t lyshark\n").group()
'\t'
>>> re.search(r"\\","hello\\lyshark").group()
'\\'

定期的な記号([]):一致検索データ範囲が指定され、通常は[0-9] [a-z] [A-Z]これらの形式に一致します。

>>> re.search("[0-9]","hello 1,2,3,4,5").group()
'1'
>>> re.findall("[0-9]","hello 1,2,3,4,5")
['1', '2', '3', '4', '5']
>>> re.search("[^0-9]","hello 1,2,3,4,5").group()
'h'
>>> re.search("[a-z]","hello 1,2,3,4,5").group()
'h'
>>> re.search("^[a-z]","hello 1,2,3,4,5").group()
'h'
>>> re.search("[^a-z]","hello 1,2,3,4,5").group()
' '
>>> re.search("[^A-Z]","hello 1,2,3,4,5").group()
'h'


一般的な境界マッチング

文法 解決するには、ワイルドカードのマッチングアクション
他のデフォルトの試合\n任意の文字よりも、指定された場合にはflag=DOTALL改行を含む任意の文字に一致、
^ 試合に指定された文字データ、検索(R "^ A"、 "\ NABC \ neee"、フラグ= re.MULTILINE)の始まり
$ 指定された文字データ、検索( "FOO $"、 "bfooの\のnsdfsf"、フラグ= re.MULTILINE).groupの末尾にマッチ()
* マッチング*番号の前の文字を0回以上、のfindAll( "AB *"、 "cabb3abcbbac") 結果[ 'ABB'、 'AB' 、 'A']
+ 試合前の文字1回以上、のfindAll( "AB +"、 "AB + CDの+ ABB + BBA")結果[ 'AB'、 'ABB']
先行文字1または0回のfindAll( "AB?"、 "AB、ABC、ABCDE")結果[ 'AB'、 ''、 'AB'、 'A-B']と一致
縦線 マッチの選択は、左または右の文字の縦線、検索(「ABC垂直ABC」、「ABCBabcCD」)。グループ()の結果[「ABC」]
{M} マッチは、m番目の文字、検索( "ハロー{2}"、「こんにちは、helloo).group()結果[ 'helloo']前に発生しました
{N、M} 文字試合前に、n回が起こってきた、最もm回でありました
(?P ...) グループマッチング、検索(「(?P [A-ZA-Z] +)(?P [0-9] +)」、 "lyshark22")。groupdict( "TEMP")

正規のシンボル(^$): ^指定された文字データの先頭にマッチし$た文字の指定した番号の末尾にマッチします。

>>> re.search(r"^h","hello world")
<re.Match object; span=(0, 1), match='h'>
>>> re.search(r"^h","hello world").group()
'h'

>>> re.search(r"world$","hello\nworld")
<re.Match object; span=(6, 11), match='world'>
>>> re.search(r"world$","hello\nworld").group()
'world'

正規のシンボル(*):前のアスタリスク文字は0、または任意の回数現れると一致します。

>>> re.findall("ab*","abccba23acbcabb")
['ab', 'a', 'a', 'abb']

定期的な記号は(+):少なくとも一度、直前の文字が現れマッチプラス1回、または任意の回数。

>>> re.findall("ab+","abccba23acbcabb")
['ab', 'abb']

定期的な記号(?):文字は一度登場し、または0回0回許さ元試合。

>>> re.findall("ab?","ab,abc,abb,abcd,a,acd,abc")
['ab', 'ab', 'ab', 'ab', 'a', 'a', 'ab']

>>> re.findall("ab?","ab,a,abc,abcde")
['ab', 'a', 'ab', 'ab']

定期的な記号(|):マッチの選択、垂直左、右、または任意の場合インチ

>>> re.search("abc|ABC","ABCBabcCD").group()
'ABC'

>>> re.findall("abc|ABC","ABCBabcCD")
['ABC', 'abc']

定期的な符号は(x{m}):直前の文字xにマッチし、ラインm回がありました。

>>> re.search("hello{2}","hello,helloo,hellooo,helloooo").group()
'helloo'

>>> re.search("hello{3}","hello,helloo,hellooo,helloooo").group()
'hellooo'

定期的な符号は(x{n,m}):直前の文字xにマッチし、少なくともn回登場し、m回にそこまでされています。

>>> re.search("hello{1,2}","hello,helloo,hellooo,helloooo").group()
'hello'

>>> re.findall("hello{1,2}","hello,helloo,hellooo,helloooo")
['hello', 'helloo', 'helloo', 'helloo']

定期的な記号((?P<name>...)):マッチと自動的にグループ化し、関連する条件、およびその結果、プリントアウト?P<..>、正規のルールに続く文言を、固定されています。

>>> number = "371481199306143242"
>>> re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})",number).groupdict()
{'province': '3714', 'city': '81', 'birthday': '1993'}

>>> re.search("(?P<name>[a-zA-Z]+)(?P<age>[0-9]+)","lyshark22").groupdict("temp")
{'name': 'lyshark', 'age': '22'}


一般的なマッチング機能

関数名やメソッド名 解決するには、ワイルドカードのマッチングアクション
regex.match ゼロ以上の文字が一致した場合、文字列の位置の先頭から一致検索は、対応する一致オブジェクトが返されます。ないなしが返されない場合。
regex.search 文字列の最初の出現に直接位置を見つけるために、文字列全体のマッチングをスキャンし、一致がNoneが返されていない障害が発生した場合、対応する一致するオブジェクトを返します。
regex.findall すべてのサブ検索文字列と文字列にマッチする正規表現、それが一致するすべての結果の文字列を見つけること、あり、そしてリストとしてデータを返します。
regex.sub また、文字列は、単純に、正規表現のマッチングとストリングの指定した数を交換され、最後に変更された文字列の置き換えを返します。
regex.split 文字列を分割するセパレータとして正規表現に一致する文字列を、分割された各文字列は、リスト形式を返します。
match.expand 新しい文字列を作成し、マッチングによって得られたオブジェクトを返すために、一致しないパケットは空の文字列に置き換えられます。
match.group 単一のパラメータ文字列が返された場合、マルチパラメータはタプルを返し、コンテンツをキャプチャするためにマッチした、1つ以上の指定グループを返します。
match.groups これは、パケットがコマンドの内容、defalultを指定された値と一致しない場合、タプルは、すべてのパケットにマッチし返します。
match.groupdict これは、パケットがデフォルト値に内容が一致しない場合はすべての名前と辞書のオブジェクトの名前を含むパケットは、コンテンツにマッチした返されます。

regex.match(): 从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None.

match(pattern,string,flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# falgs  : 匹配模式
#------------------------------------------------
#  未分组情况下.
>>> origin = "hello alex bcd abcd lge acd 19"
>>>
>>> ret = re.match("h\w+",origin)
>>> print(ret.group())                 #获取匹配到的所有结果
>>> print(ret.groups())                #获取模型中匹配到的分组结果
>>> print(ret.groupdict())             #获取模型中匹配到的分组结果
#------------------------------------------------
#  有分组情况下. 提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
>>> ret = re.match("h(\w+).*(?P<name>\d)$",origin)
>>> print(r.group())                   #获取匹配到的所有结果
>>> print(r.groups())                  #获取模型中匹配到的分组结果
>>> print(r.groupdict())               #获取模型中匹配到的分组中所有执行了key的组

regex.search(): 搜索整个字符串去匹配第一个符合条件的数据,未匹配成功返回None.

>>> origin = "hello alex bcd abcd lge acd 19"
>>>
>>> re.search("^h\w+",origin).group()          #匹配开头是h的后面是任意字符的
'hello'
>>> re.search("a\w+",origin).group()           #匹配a开头后面是任意字符的
'alex'
>>> re.search("(?P<name>a\w+)",origin).groupdict()
{'name': 'alex'}                               #分组匹配并过滤出alex

>>> re.search("(?P<姓名>[a-zA-Z]+)(?P<年龄>[0-9]+)","lyshark22").groupdict()
{'姓名': 'lyshark', '年龄': '22'}               #匹配字符串,并分组打印出结果

regex.findall(): 获取非重复的匹配列表,如果有一个组则以列表形式返回,且每一个匹配均是字符串,空的匹配也会包含在结果中.

>>> origin = "hello alex bcd abcd lge acd 19"

>>> re.findall("al\w+",origin)
['alex']                             #匹配到单个结果,则以单列表返回
>>> re.findall("a\w+",origin)
['alex', 'abcd', 'acd']              #匹配到多个结果,则以列表形式返回

regex.sub(): 先匹配查找结果,然后进行字串的替换,也就是替换匹配成功的指定位置字符串.

sub(pattern,repl,string,count=0,flags=0)
# pattern: 正则模型
# repl   : 要替换的字符串或可执行对象
# string : 要匹配的字符串
# count  : 指定匹配个数
# flags  : 匹配模式

>>> origin = "hello alex bcd abcd lge acd 19"

>>> re.sub("a[a-z]+","999999",origin,1)      #匹配以a开头则字串,并替换成9999,替换1次
'hello 999999 bcd abcd lge acd 19'
>>> re.sub("a[a-z]+","999999",origin,2)      #匹配以a开头则字串,并替换成9999,替换2次
'hello 999999 bcd 999999 lge acd 19'

regex.split(): 字符串切割函数,用来实现对指定字符串的分割工作,根据正则匹配分割字符串.

split(pattern,string,maxsplit=0,flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# maxsplit:指定分割个数
# flags  : 匹配模式

>>> origin = "hello alex bcd abcd lge acd 19"

>>> re.split("alex",origin,1)               #无分组切割
['hello ', ' bcd abcd lge acd 19']
>>> re.split("(alex)",origin,1)             #有分组,以alex最为分隔符,切割字符串
['hello ', 'alex', ' bcd abcd lge acd 19']

常用匹配: 下面举几个小例子,分别用来匹配IP地址,手机号,和邮箱地址.

IP:
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$

手机号:
^1[3|4|5|8][0-9]\d{8}$

邮箱:
[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+


Flage 标识位

re.DOTALL

# 正则表达式默认以单行开始匹配的
import re

def re_pattern_syntax():
    # .表示任意单一字符
    # *表示前一个字符出现>=0次
    # re.DOTALL就可以匹配换行符\n,默认是以行来匹配的
    print(re.match(r'.*', 'abc\nedf').group())
    print('*' * 80)
    print(re.match(r'.*', 'abc\nedf',re.DOTALL).group())

if __name__ == '__main__':
    re_pattern_syntax()

re.MULTILINE

# 正则表达式默认以单行开始匹配的
import re

def re_pattern_syntax1():
    # ^表示字符串开头(单行)
    # re.MULTILINE多行匹配字符串开头
    print(re.findall(r'^abc', 'abc\nedf'))
    print('*' * 80)
    print(re.findall(r'^abc', 'abc\nabc',re.MULTILINE))

def re_pattern_syntax2():
    # $表示字符串结尾
    # re.MULTILINE表示行的结束
    print(re.findall(r'abc\d$', 'abc1\nabc2'))
    print('*' * 80)
    print(re.findall(r'abc\d$', 'abc1\nabc2',re.MULTILINE))

if __name__ == '__main__':
    re_pattern_syntax1()
    re_pattern_syntax2()

?非贪婪模式

import re

def re_pattern_syntax4():
    # greedy贪婪/non-greedy非贪婪,默认的是贪婪的匹配
    s = '<H1>title</H1>'
    print(re.match(r'<.+>', s).group())  #贪婪模式会匹配尽量多的匹配
    print(re.match(r'<.+?>', s).group()) #非贪婪模式匹配尽量少的匹配
    print(re.match(r'<(.+)>', s).group(1))
    print(re.match(r'<(.+?)>', s).group(1))

def re_pattern_syntax5():
    # {m}/{m,}/{m,n}
    print(re.match(r'ab{2,4}', 'abbbbbbb').group())  #贪婪模式尽量匹配多
    print(re.match(r'ab{2,4}?', 'abbbbbbb').group()) #非贪婪模式尽量匹配少
    print('*' * 80)

if __name__ == '__main__':
    re_pattern_syntax4()
    re_pattern_syntax5()

re.I/re.IGNORECASE

import re

def re_pattern_flags():
    # re.I/re.IGNORECASE
    print(re.match(r'(Name)\s*:\s*(\w+)','NAME : Joey',re.IGNORECASE).groups())
    print('*' * 80)

if __name__ == '__main__':
    re_pattern_syntax_meta_char()

re.VERBOSE

import re

def re_pattern_flags1():
    # re.VERBOSE此标识位可以添加注释/re.compile
    s = 'the number is 20.5'
    r = re.compile(r'''
                    \d+   # 整数部分
                    \.?   # 小数点,可能包含也可能不包含
                    \d*   # 小数部分,可选
                    ''',re.VERBOSE)
    print(re.search(r,s).group())
    print(r.search(s).group())
    print('*' * 80)

if __name__ == '__main__':
    re_pattern_syntax_meta_char1()


有无分组比较

re.mach()

# 无分组
r = re.match("h\w+", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果

# 有分组
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
r = re.match("h(\w+).*(?P<name>\d)$", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组

re.search()

# 无分组
r = re.search("a\w+", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果
 
# 有分组
r = re.search("a(\w+).*(?P<name>\d)$", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组

re.findall()

# 无分组
r = re.findall("a\w+",origin)
print(r)

# 有分组
origin = "hello alex bcd abcd lge acd 19"
r = re.findall("a((\w*)c)(d)", origin)
print(r)

re.split()

# 无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.split("alex", origin, 1)
print(r)

# 有分组
origin = "hello alex bcd alex lge alex acd 19"
r1 = re.split("(alex)", origin, 1)
print(r1)
r2 = re.split("(al(ex))", origin, 1)
print(r2)

常用例子

import re
print(re.findall(r'(\d+)-([a-z])','34324-dfsdfs777-hhh'))       # [('34324', 'd'), ('777', 'h')]
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(0))    # 34324-d 返回整体
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(1))    # 34324 获取第一个组
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(2))    # d 获取第二个组
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(3))    # IndexError: no such group
  
print(re.search(r"(jason)kk\1","xjasonkkjason").group())        #\1表示应用编号为1的组 jasonkkjason
print(re.search(r'(\d)gg\1','2j333gg3jjj8').group())                 # 3gg3 \1表示使用第一个组\d
  
# 下面的返回None 为什么是空?而匹配不到3gg7,因为\1的不仅表示第一组,而且匹配到的内容也要和第一组匹配到的内容相同,第一组匹配到3,第二组匹配到7 不相同所以返回空
print(re.search(r'(\d)gg\1','2j333gg7jjj8'))
print(re.search(r'(?P<first>\d)abc(?P=first)','1abc1'))             # 1abc1 声明一个组名,使用祖名引用一个组 

r=re.match('(?P<n1>h)(?P<n2>\w+)','hello,hi,help')   # 组名的另外一种用法
print(r.group())                                # hello 返回匹配到的值
print(r.groups())                               # ('h', 'ello')返回匹配到的分组
print(r.groupdict())                            # {'n2': 'ello', 'n1': 'h'} 返回分组的结果,并且和相应的组名组成一个字典

# 分组是从已经匹配到的里面去取值
origin ="hello alex,acd,alex"
print(re.findall(r'(a)(\w+)(x)',origin))                  # [('a', 'le', 'x'), ('a', 'le', 'x')]
print(re.findall(r'a\w+',origin))                         # ['alex', 'acd', 'alex']
print(re.findall(r'a(\w+)',origin))                       # ['lex', 'cd', 'lex']
print(re.findall(r'(a\w+)',origin))                       # ['alex', 'acd', 'alex']
print(re.findall(r'(a)(\w+(e))(x)',origin))               # [('a', 'le', 'e', 'x'), ('a', 'le', 'e', 'x')]

r=re.finditer(r'(a)(\w+(e))(?P<name>x)',origin)
for i in r :
    print(i,i.group(),i.groupdict())
'''
    [('a', 'le', 'e', 'x'), ('a', 'le', 'e', 'x')]
    <_sre.SRE_Match object; span=(6, 10), match='alex'> alex {'name': 'x'}
    <_sre.SRE_Match object; span=(15, 19), match='alex'> alex {'name': 'x'}
'''

print(re.findall('(\w)*','alex'))                   # 匹配到了alex、但是4次只取最后一次即 x 真实括号只有1个
print(re.findall(r'(\w)(\w)(\w)(\w)','alex'))       # [('a', 'l', 'e', 'x')]  括号出现了4次,所以4个值都取到了
  
origin='hello alex sss hhh kkk'
print(re.split(r'a(\w+)',origin))                   # ['hello ', 'lex', ' sss hhh kkk']
print(re.split(r'a\w+',origin))                     # ['hello ', ' sss hhh kkk']


おすすめ

転載: www.cnblogs.com/LyShark/p/11297591.html