#python #regex
Вопрос:
Есть задача по набору персонала, которую я хотел решить просто с помощью регулярных выражений.
Предложение состоит из группы слов. Каждое слово состоит из букв [a-zA-Z]
, которые могут содержать один или несколько тире и могут заканчиваться знаком препинания, таким как точка (.), запятая (,), знак вопроса (?) или восклицательный знак (!). Каждое слово не может начинаться ни с одной буквы или цифры. Также принимается одна буква, разделенная пробелами.
Тире соединяют два или более слов в одно и должны быть приняты (но двойные тире «—» и больше нет), в то время как другие допустимые знаки препинания в конце слова должны быть удалены.
Допустимые слова (примеры):
- «фу-фу?!.»: результат = «фу-фу»,
- «фу-фу-фу?!.»: результат = «фу-фу-фу»,
Недопустимые слова (примеры):
- «!@foo-foo{{}}}((«
- «фу-фу»
- «фу-фу@ — @фу»
- «ф123-фу-фу-фу -«
- «- фу-фу-фу…»
Я попытался решить проблему на python только с помощью регулярных выражений:
import re
TESTSTR1 = 'there should be 9 valid words, including: a well-behave, right?'
TESTSTR2 = 'blabla! bla121 {{blabla123bla.. bla-blablabla!! b;a-bla@!. blabla bla-bla-bla-bla **bla-bla'
TESTSTR3 = '{{)foo! ~~foo121 foo--foo?. foo-foo?!{. @foo-foo! f 23 foo2 f-ff-fff-ffff!.,? **foo-f'
TESTSTR1_EXPECTED = ['there', 'should', 'be', 'valid', 'words', 'including', 'a', 'well-behave','right']
TESTSTR2_EXPECTED = ['blabla', 'bla-blablabla', 'blabla', 'bla-bla-bla-bla', 'bla-bla']
TESTSTR3_EXPECTED = ['f', 'f-ff-fff-ffff','foo-f']
def find_words(sentence: str) -> list:
pattern_dash = r'b([^ds] (?:-w [a-zA-Z]*))b'
pattern = r'b(?!w -w )(?!-w )[a-zA-Z] b'
words = re.findall(pattern_dash, sentence)
words = re.findall(pattern, sentence)
return words
if __name__ == "__main__":
print('====================== TEST1 ======================')
print(f'Expected "TESTSTR1" = {TESTSTR1_EXPECTED}')
print(f'Result "TESTSTR1" = {find_words(TESTSTR1)}')
print('====================== TEST2 ======================')
print(f'Expected "TESTSTR2" = {TESTSTR2_EXPECTED}')
print(f'Result "TESTSTR2" = {find_words(TESTSTR2)}')
print('====================== TEST3 ======================')
print(f'Expected "TESTSTR3" = {TESTSTR3_EXPECTED}')
print(f'Result "TESTSTR3" = {find_words(TESTSTR3)}')
Сначала я хотел найти все допустимые слова, содержащие символ тире («pattern_dash»), а затем все остальные допустимые слова (за исключением уже найденных).
Я перепробовал множество различных комбинаций регулярных выражений, но безуспешно. Я не уверен, что задача решаема только с помощью регулярных выражений.
Кто-нибудь знает, можно ли решить эту проблему, используя только регулярное выражение? У вас есть какие-нибудь идеи, как это сделать?
Большое спасибо
Ответ №1:
Чтобы получить совпадения в данных примера, вы можете использовать группу захвата.
Сначала сопоставьте пробел или *
, затем запишите слова только с A-Za-z, необязательно разделенными -
, и подтвердите, что слова заканчиваются пробелом, концом строки или 1 или более знаками препинания, за которыми следует граница пробела справа.
(?:[ *]|^)([a-zA-Z] (?:-[a-zA-Z] )*)(?= |$|[.,!?:] (?!S))
По частям шаблон совпадает:
(?:[ *]|^)
Не группа захвата, соответствует или*
или утверждает начало строки(
Группа захвата 1[a-zA-Z]
Совпадение 1 вхождений A-Za-z(?:-[a-zA-Z] )*
При необходимости повторите то же самое еще раз перед-
)
Близкая группа 1(?=
Позитивный взгляд, утверждайте, что прямо справа находится|
Или$
Утвердите конец строки|
Или[.,!?:] (?!S)
Сопоставьте 1 или более вхождений из класса символов[.,!?:]
и установите границу пробела справа
)
Близкий взгляд
Смотрите демонстрацию регулярных выражений и демонстрацию Python
Например
import re
strings = [
"there should be 9 valid words, including: a well-behave, right?",
"blabla! bla121 {{blabla123bla.. bla-blablabla!! b;a-bla@!. blabla bla-bla-bla-bla **bla-bla",
"{{)foo! ~~foo121 foo--foo?. foo-foo?!{. @foo-foo! f 23 foo2 f-ff-fff-ffff!.,? **foo-f"
]
pattern = r"(?:[ *]|^)([a-zA-Z] (?:-[a-zA-Z] )*)(?= |$|[.,!?:] (?!S))"
for s in strings:
print(re.findall(pattern, s, re.M))
Выход
['there', 'should', 'be', 'valid', 'words', 'including', 'a', 'well-behave', 'right']
['blabla', 'bla-blablabla', 'blabla', 'bla-bla-bla-bla', 'bla-bla']
['f', 'f-ff-fff-ffff', 'foo-f']