- Регулярные выражения (Regex) в Python
- поиск
- группирование
- Именованные группы
- Не захватывающие группы
- Экранирование специальных персонажей
- Замена
- Замена строк
- Использование групповых ссылок
- Использование функции замены
- Найти все неперекрывающиеся совпадения
- Предварительно скомпилированные шаблоны
- Проверка на допустимые символы
- Разделение строки с помощью регулярных выражений
- Флаги
- Ключевое слово флаги
- Встроенные флаги
- Перебор совпадений с использованием `re.finditer`
- Соответствовать выражению только в определенных местах
Регулярные выражения (Regex) в Python
Первый аргумент re.match() является регулярным выражением, вторая строка , чтобы соответствовать:
import re pattern = r"123" string = "123zzb" re.match(pattern, string) # Out: match = re.match(pattern, string) match.group() # Out: '123'
Можно заметить , что переменная шаблона представляет собой строку с префиксом r , что указывает на то, что строка является исходным строка символов.
Сырые строковый литерал имеет несколько иного синтаксис , чем строка буквального, а именно обратный слэш \ в сыре строковых литералов означает «только обратной косой черты» , и нет никакой необходимости удвоения люфтов , чтобы избежать «экранирующих последовательностей» , такие как символ новой строки ( \n ) , вкладки ( \t ), забой ( \ ), формы-каналы ( \r ), и так далее. В обычных строковых литералах каждый обратный слеш должен быть удвоен, чтобы его не принимали за начало escape-последовательности.
Следовательно, r»\n» является строкой из 2 -х символов: \ и n .Regex модель также использовать обратную косую черту, например , \d относится к любому цифровому символу. Мы можем избежать того , чтобы удвоить наши избежать строки ( «\\d» ) с использованием сырьевых строк ( r»\d» ).
string = "\\t123zzb" # here the backslash is escaped, so there's no tab, just '\' and 't' pattern = "\\t123" # this will match \t (escaping the backslash) followed by 123 re.match(pattern, string).group() # no match re.match(pattern, "\t123zzb").group() # matches '\t123' pattern = r"\\t123" re.match(pattern, string).group() # matches '\\t123'
Сопоставление выполняется только с начала строки. Если вы хотите , чтобы соответствовать в любом месте использовать re.search вместо:
match = re.match(r"(123)", "a123zzb") match is None # Out: True match = re.search(r"(123)", "a123zzb") match.group() # Out: '123'
поиск
pattern = r"(your base)" sentence = "All your base are belong to us." match = re.search(pattern, sentence) match.group(1) # Out: 'your base' match = re.search(r"(belong.*)", sentence) match.group(1) # Out: 'belong to us.'
Поиск осуществляется в любом месте строки , в отличие от re.match .Вы можете также использовать re.findall .
Вы можете также искать в начале строки (используйте ^ ),
match = re.search(r"^123", "123zzb") match.group(0) # Out: '123' match = re.search(r"^123", "a123zzb") match is None # Out: True
в конце строки (используйте $ ),
match = re.search(r"123$", "zzb123") match.group(0) # Out: '123' match = re.search(r"123$", "123zzb") match is None # Out: True
или оба (использовать оба ^ и $ ):
match = re.search(r"^123$", "123") match.group(0) # Out: '123'
группирование
Группировка осуществляется с помощью скобок. Вызов group() возвращает строку , образованную из согласующих скобок подгрупп.
match.group() # Group without argument returns the entire match found # Out: '123' match.group(0) # Specifying 0 gives the same result as specifying no argument # Out: '123'
Аргументы могут также быть предоставлена group() для извлечения конкретной подгруппы.
Если есть единственный аргумент, результат — единственная строка; если имеется несколько аргументов, результатом является кортеж с одним элементом на аргумент.
Вызов groups() , с другой стороны, возвращает список кортежей , содержащих подгруппу.
sentence = "This is a phone number 672-123-456-9910" pattern = r".*(phone).*?([\d-]+)" match = re.match(pattern, sentence) match.groups() # The entire match as a list of tuples of the paranthesized subgroups # Out:('phone', '672-123-456-9910') m.group() # The entire match as a string # Out: 'This is a phone number 672-123-456-9910' m.group(0) # The entire match as a string # Out: 'This is a phone number 672-123-456-9910' m.group(1) # The first parenthesized subgroup. # Out: 'phone' m.group(2) # The second parenthesized subgroup. # Out: '672-123-456-9910' m.group(1, 2) # Multiple arguments give us a tuple. # Out:('phone', '672-123-456-9910')
Именованные группы
match = re.search(r'My name is (?P[A-Za-z ]+)', 'My name is John Smith') match.group('name') # Out: 'John Smith' match.group(1) # Out: 'John Smith'
Создает группу захвата, на которую можно ссылаться как по имени, так и по индексу.
Не захватывающие группы
Используя (?:) создает группу, но группа не улавливается. Это означает, что вы можете использовать его как группу, но это не будет загрязнять ваше «групповое пространство».
re.match(r'(\d+)(\+(\d+))?', '11+22').groups() # Out:('11', '+22', '22') re.match(r'(\d+)(?:\+(\d+))?', '11+22').groups() # Out:('11', '22')
Этот пример соответствует 11+22 или 11 , но не 11+ .Это так + знак и второй член сгруппированы. С другой стороны, + знак не улавливается.
Экранирование специальных персонажей
Специальные символы (например , класса символов скобки [ и ] ниже) не соответствуют буквально:
match = re.search(r'[b]', 'a[b]c') match.group() # Out: 'b'
Избегая специальных символов, они могут быть сопоставлены буквально:
match = re.search(r'\[b\]', 'a[b]c') match.group() # Out: '[b]'
re.escape() функция может использоваться , чтобы сделать это для вас:
re.escape('a[b]c') # Out: 'a\\[b\\]c' match = re.search(re.escape('a[b]c'), 'a[b]c') match.group() # Out: 'a[b]c'
re.escape() функция экранирует все специальные символы, так что это полезно , если вы составляете регулярное выражение на основе пользовательского ввода:
username = 'A.C.' # suppose this came from the user re.findall(r'Hi <>!'.format(username), 'Hi A.C.! Hi ABCD!') # Out: ['Hi A.C.!', 'Hi ABCD!'] re.findall(r'Hi <>!'.format(re.escape(username)), 'Hi A.C.! Hi ABCD!') # Out: ['Hi A.C.!']
Замена
Замены могут быть сделаны на строки , используя re.sub .
Замена строк
re.sub(r"t58", "foo", "my name t13 is t44 what t99 ever t44") # Out: 'my name foo is foo what foo ever foo'
Использование групповых ссылок
Замены с небольшим количеством групп можно сделать следующим образом:
re.sub(r"t(6)(9)", r"t\2\1", "t13 t19 t81 t25") # Out: 't31 t91 t18 t52'
Тем не менее, если вы сделаете идентификатор группы , как «10», это не работает : \10 читаются как «идентификационный номер 1 с последующим 0». Таким образом , вы должны быть более конкретными и использовать \g обозначения:
re.sub(r"t(1)(4)", r"t\g\g", "t13 t19 t81 t25") # Out: 't31 t91 t18 t52'
Использование функции замены
items = ["zero", "one", "two"] re.sub(r"a\[(2)\]", lambda match: items[int(match.group(1))], "Items: a[0], a[1], something, a[2]") # Out: 'Items: zero, one, something, two'
Найти все неперекрывающиеся совпадения
re.findall(r"5", "some 1 text 12 is 945 here 4445588899") # Out: ['12', '945', '444', '558', '889']
Обратите внимание , что r перед тем «2» говорит Python интерпретировать строку как есть; как «сырая» строка.
Вы можете также использовать re.finditer() , которая работает точно так же , как re.findall() , но возвращает итератор с SRE_Match объектов вместо списка строк:
results = re.finditer(r"(8)", "some 1 text 12 is 945 here 4445588899") print(results) # Out: for result in results: print(result.group(0)) ''' Out: 12 945 444 558 889 '''
Предварительно скомпилированные шаблоны
import re precompiled_pattern = re.compile(r"(\d+)") matches = precompiled_pattern.search("The answer is 41!") matches.group(1) # Out: 41 matches = precompiled_pattern.search("Or was it 42?") matches.group(1) # Out: 42
Компиляция шаблона позволяет использовать его позже в программе. Тем не менее, обратите внимание , что Python кэширует недавно использованные выражения ( документы , SO ответить ), поэтому «программы , которые используют только несколько регулярных выражений в то время , не нужно беспокоиться о составлении регулярных выражений».
import re precompiled_pattern = re.compile(r"(.*\d+)") matches = precompiled_pattern.match("The answer is 41!") print(matches.group(1)) # Out: The answer is 41 matches = precompiled_pattern.match("Or was it 42?") print(matches.group(1)) # Out: Or was it 42
Может использоваться с re.match ().
Проверка на допустимые символы
Если вы хотите проверить, что строка содержит только определенный набор символов, в этом случае az, AZ и 0-9, вы можете сделать это следующим образом:
import re def is_allowed(string): characherRegex = re.compile(r'[^a-zA-Z0-9.]') string = characherRegex.search(string) return not bool(string) print(is_allowed("abyzABYZ0099")) # Out: 'True' print(is_allowed("#*@#$%^")) # Out: 'False'
Вы также можете адаптировать выражение линию из [^a-zA-Z0-9.] На [^a-z0-9.] , Чтобы запретить прописные буквы, например.
Частичный кредит: https://codecamp.ru/a/1325265/2697955
Разделение строки с помощью регулярных выражений
Вы также можете использовать регулярные выражения, чтобы разбить строку. Например,
import re data = re.split(r'\s+', 'James 94 Samantha 417 Scarlett 74') print( data ) # Output: ['James', '94', 'Samantha', '417', 'Scarlett', '74']
Флаги
В некоторых особых случаях нам нужно изменить поведение регулярного выражения, это делается с помощью флагов. Флаги могут быть установлены двумя способами, через flags ключевого слова или непосредственно в выражении.
Ключевое слово флаги
Ниже приведен пример для re.search , но это работает для большинства функций в re модуле.
m = re.search("b", "ABC") m is None # Out: True m = re.search("b", "ABC", flags=re.IGNORECASE) m.group() # Out: 'B' m = re.search("a.b", "A\nBC", flags=re.IGNORECASE) m is None # Out: True m = re.search("a.b", "A\nBC", flags=re.IGNORECASE|re.DOTALL) m.group() # Out: 'A\nB'
Общие флаги
Флаг Краткое описание re.IGNORECASE , re.I Заставляет шаблон игнорировать случай re.DOTALL , re.S Делает . сопоставить все, включая переводы строк re.MULTILINE , re.M Делает ^ соответствовать началу строки и $ конца строки re.DEBUG Включает отладочную информацию
Для полного списка всех доступных флагов проверить документы
Встроенные флаги
(?iLmsux) (один или более букв из набора ‘I’, ‘L’, ‘м’, ‘S’, ‘и’, ‘х’.)
Группа соответствует пустой строке; буквы устанавливают соответствующие флаги: re.I (игнорировать регистр), re.L (зависит от локали), re.M (многострочный), re.S (точка соответствует всем), re.U (зависит от Unicode) и re.X (многословный), для всего регулярного выражения. Это полезно, если вы хотите включить флаги как часть регулярного выражения вместо передачи аргумента флага в функцию re.compile ().
Обратите внимание, что флаг (? X) изменяет способ анализа выражения. Его следует использовать сначала в строке выражения или после одного или нескольких пробельных символов. Если перед флагом есть непробельные символы, результаты не определены.
Перебор совпадений с использованием `re.finditer`
Вы можете использовать re.finditer перебрать все матчи в строке. Это дает вам (по сравнению с re.findall дополнительной информации, например, информации о местоположении матча в строке (индексы):
import re text = 'You can try to find an ant in this string' pattern = 'an?\w' # find 'an' either with or without a following word character for match in re.finditer(pattern, text): # Start index of match (integer) sStart = match.start() # Final index of match (integer) sEnd = match.end() # Complete match (string) sGroup = match.group() # Print match print('Match "<>" found at: [<>,<>]'.format(sGroup, sStart,sEnd))
Match "an" found at: [5,7] Match "an" found at: [20,22] Match "ant" found at: [23,26]
Соответствовать выражению только в определенных местах
Часто вы хотите , чтобы соответствовать выражение только в определенных местах (оставляя их нетронутыми в других, то есть). Рассмотрим следующее предложение:
An apple a day keeps the doctor away (I eat an apple everyday).
Здесь «яблоко» встречается дважды , которые могут быть решены с помощью так называемым отслеживанием источников глаголов управления , которые поддерживаются в новом regex модуля. Идея заключается в следующем:
forget_this | or this | and this as well | (but keep this)
На нашем примере с яблоком это будет:
import regex as re string = "An apple a day keeps the doctor away (I eat an apple everyday)." rx = re.compile(r''' \([^()]*\) (*SKIP)(*FAIL) # match anything in parentheses and "throw it away" | # or apple # match an apple ''', re.VERBOSE) apples = rx.findall(string) print(apples) # only one
Это соответствует «яблоку» только тогда, когда его можно найти за скобками.
- Глядя слева направо, регулярное выражение двигатель потребляет все , чтобы слева, (*SKIP) действует как «всегда-истинным самоутверждения». После этого, он правильно не работает на (*FAIL) и откатывается.
- Теперь он попадает в точку (*SKIP) справа налево (он же в то время как возвратов) , где запрещено идти дальше влево. Вместо этого, двигатель сказал , чтобы выбросить что — нибудь налево и перейти к точке , где (*SKIP) был вызван.