Как регулярное выражение с |? - PullRequest
3 голосов
/ 09 ноября 2019
import re
s6 = '''Male : abc
   Male : def'''
re.findall(r'(.*):|:(.*)', s6)

Мой вывод:

[('Male ', ''), ('            Male ', '')]

Мой ожидаемый вывод:

[('Male','abc'),('Male','def')]

Когда я делаю re.findall(r'(.*):', s6) Я получаю ['Male ', ' Male '] и с re.findall(r':(.*)', s6) Яполучая [' abc', ' def']. Когда я использую символ |, я получаю неправильный вывод.

Отказ от ответственности: Пожалуйста, не делайте re.split

Я также сделал \w+, который работает, но яхочу выражение в следующем формате. Я сделал re.findall(r'\s*(\w+)\s*:|:\s*(\w+)', s6), который не работает по отдельности. С \s*(\w+)\s*: и :\s*(\w+)', s6 это работает.

Я хочу знать, почему с | он не работает.

Ответы [ 5 ]

4 голосов
/ 09 ноября 2019

Оператор чередования | говорит "соответствует этому регулярному выражению или соответствует этому регулярному выражению". Два подвыражения не могут совпадать одновременно. Если первое совпадение, второе никогда не будет проверено.

Чтобы извлечь материал с обеих сторон двоеточия, просто создайте регулярное выражение, которое захватывает текст с обеих сторон в одном совпадении.

re.findall(r'([^\n:]+):([^\n:]+)', s6)

Чтобы обрезать пропуски вокруг совпадений, вам нужно более сложное регулярное выражение, за исключением, разумеется, если вы знаете, что совпадающие строки всегда будут одним токеном (т. Е. Каждая представляет собой одну алфавитную строку без пробелов вit):

re.findall(r'(\w+)\s*:\s*(\w+)', s6)

Может быть, для нескольких токенов попробуйте

re.findall(r'\s*([^\n:]+?)\s*:\s*([^\n:]+?)(?=\s*(?:\n|$))', s6)

, где мы очень заметно чередуем жадное и не жадное сопоставление, чтобы получить максимально короткие строки, которые по-прежнему удовлетворяют обычнымВыражение.

Или вы можете развернуться и превратить жадность в свое преимущество:

re.findall(r'(\w+(?:[^\n\S]+\w+)*)\s*:\s*(\w+(?:[^\n\S]+\w+)*)', s6)

, где мы собираем столько захваченных пробелами токенов, сколько мы можем в захвате, до тех пор, покапробел не содержит новой строки.

Более подробно, e+ соответствует как можно большему количеству (жадный соответствия) и e+? как можно меньше (не жадный или скупой соответствие). (?=...) - это запрос, требующий соответствия следующего выражения, без захвата или использования соответствующего текста. Таким образом, e(?=e) применительно к тексту eee сначала будет соответствовать начальному e, а на следующей итерации findall найдет сразу следующую, даже если он уже участвовал в удовлетворениипредыдущий матчИ, конечно же, (?:...) - это простая не захватывающая скобка для группировки, а [^\n\S] - это класс символов, который соответствует любому символу, который не является символом новой строки и ... не не членомкатегория пробелов - так эффективно любые пробелы, кроме новой строки.

Обратите внимание также на то, как мы явно избегаем сопоставления двоеточия или новой строки в выражениях захвата.

Новичок: «Как я могу сопоставить всеэти строки? "
Мастер:" Как я могу сопоставить только эти строки? "

2 голосов
/ 09 ноября 2019

Это не работает, потому что первое совпадение потребляет ваш якорь (двоеточие), поэтому второе совпадение никогда не совпадает. Чтобы это исправить, нужны утверждения, но в данном случае это слишком сложно:

import re
compiled = re.compile(r'((\w+)\s*(?=:)|(?<=:)\s*(\w+))') 
s6 = '''Male : abc 
    Male : def''' 
re.findall(compiled, s6)                                                                                                                                                                            

# Output:
[('Male ', 'Male', ''),
 (' abc', '', 'abc'),
 ('Male ', 'Male', ''),
 (' def', '', 'def')]

Так что теперь вам нужно выполнить постобработку в вашем списке, не рекомендуется с учетом этого ввода. Вкратце: не используйте один якорь для двух случаев, используя альтернативы.

1 голос
/ 09 ноября 2019

Мы можем попытаться разбить вашу строку на один или несколько несловарных символов:

s6 = """Male : abc
Male : def"""
words = re.split(r'\W+', s6)
print(words)

['Male', 'abc', 'Male', 'def']
1 голос
/ 09 ноября 2019

Вы можете просто соответствовать тому, что вам нужно,

s6 = '''Male : abc
   Male : def'''
re.findall('[a-zA-Z]+', s6)
1 голос
/ 09 ноября 2019

Если вам нужны все слова, просто используйте '\w+':

s6 = '''Male : abc
   Male : def'''
re.findall('\w+', s6)

Вывод:

['Male', 'abc', 'Male', 'def']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...