Зразок витягу 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

1
Я отримуюNameError: name '_' is not defined
Ян G

Ваш другий рядок, я думаю, повинен прочитати _ = p.search(s). Я бачу, це згадує про встановлення результату, _але код не відображає цього. Я змінився на _ = p.search(s)другий рядок, і він працює.
Ян Г

2
@IanG Вибачте, я оновлю свою відповідь. BTW, за допомогою стандартного 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, вам потрібно буде отримати дані з групи на об'єкт відповідності:

>>> 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
Можливо, потрібна не жадібна відповідність ... (якщо в імені користувача може бути кілька слів ...)
Джон Клементс

@JonClements - Ти маєш на увазі (.*?)? Так, це можливо, хоча це і не потрібно, якщо тільки нам не користуватисяre.DOTALL
mgilson

так - re.findall('name (.*) is valid', 'name jon clements is valid is valid is valid')ймовірно, не дасть бажаних результатів ...
Джон Клементс

Це не працює для Python 2.7.1? Він просто друкує об'єкт візерунка?
Каннан Еканат

@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

Ви можете використовувати групи (вказані з '('і ')') для зйомки частин рядка. Метод об'єкта відповідності 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, але не стосується конкретного питання ОП.
Aleister Tanek Javas Mraz

Крім того, це в основному не додає нічого нового до існуючих відповідей, згадуючи синтаксис індексації 3,6+.
Євген Ярмаш

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.