Python抽出パターン一致


129

Python 2.7.1 python正規表現を使用してパターン内の単語を抽出しようとしています

このような文字列があります

someline abc
someother line
name my_user_name is valid
some more lines

「my_user_name」という単語を抽出したい。私は次のようなことをします

import re
s = #that big string
p = re.compile("name .* is valid", re.flags)
p.match(s) #this gives me <_sre.SRE_Match object at 0x026B6838>

どうすればmy_user_nameを抽出できますか?

回答:


159

正規表現からキャプチャする必要があります。searchパターンが見つかった場合は、を使用して文字列を取得しますgroup(index)。有効なチェックが実行されると仮定します:

>>> p = re.compile("name (.*) is valid")
>>> result = p.search(s)
>>> result
<_sre.SRE_Match object at 0x10555e738>
>>> result.group(1)     # group(1) will return the 1st capture.
                        # group(0) will returned the entire matched text.
'my_user_name'

26
あなたはわからないということであるgroup(0)最初のマッチのために?
sharshofski

33
ちょっと最近ですが、はいといいえの両方です。group(0)最初のキャプチャグループではなく、一致したテキストを返します。コードのコメントは正しいですが、キャプチャグループと一致を混乱させているようです。group(1)最初のキャプチャグループを返します。
andrewgu 2015

1
取得NameError: name '_' is not defined
Ian G

私が読むべきだと思うあなたの2行目_ = p.search(s)。結果の設定について言及しているようです_が、コードはそれを反映していません。_ = p.search(s)その2行目をに変更しましたが、機能します。
Ian G

2
@IanG申し訳ありませんが、回答を更新します。ところで、標準のPython REPLでは、最後の結果はという特別な変数に保存されます_。それ以外の場所では無効です。
UltraInstinct

57

一致するグループを使用できます。

p = re.compile('name (.*) is valid')

例えば

>>> import re
>>> p = re.compile('name (.*) is valid')
>>> s = """
... someline abc
... someother line
... name my_user_name is valid
... some more lines"""
>>> p.findall(s)
['my_user_name']

ここre.findallではre.search、のすべてのインスタンスを取得するのではなく、を使用していますmy_user_name。を使用re.searchして、matchオブジェクトのグループからデータを取得する必要があります。

>>> p.search(s)   #gives a match object or None if no match is found
<_sre.SRE_Match object at 0xf5c60>
>>> p.search(s).group() #entire string that matched
'name my_user_name is valid'
>>> p.search(s).group(1) #first group that match in the string that matched
'my_user_name'

コメントで述べたように、あなたは正規表現を貪欲でないようにしたいかもしれません:

p = re.compile('name (.*?) is valid')

正規表現がグループ内の他のものをピックアップすることを許可するのではなく'name '、と次の間のアイテムのみをピックアップします。' is valid'' is valid'


2
貪欲でない一致が必要になる可能性があります...(ユーザー名が複数の単語である場合を除いて...)
Jon Clements

@JonClements-つまり(.*?)?ええ、それは可能ですが、OPが使用しない限り必要ではありませんre.DOTALL
mgilson

ええ- re.findall('name (.*) is valid', 'name jon clements is valid is valid is valid')おそらく望ましい結果は得られません...
ジョン・クレメンツ

これはPython 2.7.1では機能しませんか?それはパターンオブジェクトを印刷するだけですか?
Kannan Ekanath 2013年

@CalmStorm-動作しない部分(私はpython2.7.3でテストしました)?私が使用する部分は.group、あなたが受け入れた答えとまったく同じです...
mgilson

16

あなたはこのようなものを使うことができます:

import re
s = #that big string
# the parenthesis create a group with what was matched
# and '\w' matches only alphanumeric charactes
p = re.compile("name +(\w+) +is valid", re.flags)
# use search(), so the match doesn't have to happen 
# at the beginning of "big string"
m = p.search(s)
# search() returns a Match object with information about what was matched
if m:
    name = m.group(1)
else:
    raise Exception('name not found')

10

多分それは少し短くて理解しやすいでしょう:

import re
text = '... someline abc... someother line... name my_user_name is valid.. some more lines'
>>> re.search('name (.*) is valid', text).group(1)
'my_user_name'


9

グループ('('およびで示される')')を使用して、文字列の一部をキャプチャできます。次に、matchオブジェクトのgroup()メソッドはグループのコンテンツを提供します。

>>> import re
>>> s = 'name my_user_name is valid'
>>> match = re.search('name (.*) is valid', s)
>>> match.group(0)  # the entire match
'name my_user_name is valid'
>>> match.group(1)  # the first parenthesized subgroup
'my_user_name'

Python 3.6以降では、次を使用する代わりに、一致オブジェクトにインデックスを付けることもできますgroup()

>>> match[0]  # the entire match 
'name my_user_name is valid'
>>> match[1]  # the first parenthesized subgroup
'my_user_name'

6

グループを使用せずにそれを行う方法を次に示します(Python 3.6以降):

>>> re.search('2\d\d\d[01]\d[0-3]\d', 'report_20191207.xml')[0]
'20191207'

1
これはPython Regexに対応しますが、OPの特定の質問には対応しません。
Aleister Tanek Javas Mraz

その上、これは基本的に、3.6以上の索引付け構文について言及している既存の回答に新しいものを何も追加しません。
Eugene Yarmash

3

キャプチャグループ(?P<user>pattern)を使用して、辞書のようにグループにアクセスすることもできますmatch['user']

string = '''someline abc\n
            someother line\n
            name my_user_name is valid\n
            some more lines\n'''

pattern = r'name (?P<user>.*) is valid'
matches = re.search(pattern, str(string), re.DOTALL)
print(matches['user'])

# my_user_name

1

実際に名前を抽出しようとしているようです。この場合は、一致するスパンインデックスを用意しておくと便利re.finditerです。を使用することをお勧めします。ショートカットとして、name正規表現の一部が長さ5でis valid長さが9であることを知っているので、一致するテキストをスライスして名前を抽出できます。

注-この例では、s改行付きの文字列のように見えるため、以下で想定しています。

## covert s to list of strings separated by line:
s2 = s.splitlines()

## find matches by line: 
for i, j in enumerate(s2):
    matches = re.finditer("name (.*) is valid", j)
    ## ignore lines without a match
    if matches:
        ## loop through match group elements
        for k in matches:
            ## get text
            match_txt = k.group(0)
            ## get line span
            match_span = k.span(0)
            ## extract username
            my_user_name = match_txt[5:-9]
            ## compare with original text
            print(f'Extracted Username: {my_user_name} - found on line {i}')
            print('Match Text:', match_txt)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.