2017-02-06 3 views
0

Я работаю на API Колба, который принимает следующее регулярное выражение в качестве конечной точки:python: re.search не начинается с начала строки?

([0-9]*)((OK)|(BACK)|(X))* 

Это означает, что я ожидал ряд чисел, и ОК, НАЗАД, X ключевые слова несколько раз подряд после цифр.

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

Мой подход был следующим:

endp = endp.encode('ASCII', 'ignore') 
    match = re.search(r"([0-9]*)", str(endp), re.I) 
    if match: 
     n = match.groups() 
     logging.info('nums: ' + str(n[0])) 

    match = re.search(r"((OK)|(BACK)|(X))*", str(endp), re.I) 
    if match: 
     s1 = match.groups() 
     for i in s1: 
      logging.info('str: ' + str(i[0])) 

Использование/12OK конечной точки, получить номера работает просто отлично, но по какой-то причине, захватывая остальные ключевые слова являются безуспешными. Я попытался сокращением второй группы захвата только

match = re.search(r"(OK)*", str(endp), re.I) 

Я постоянно нахожу следующее в s1 (с использованием уменьшенных регулярных выражений):

(None,) 

первоначально (с остальным ключевыми словами):

(None, None, None, None) 

Что, я думаю, означает, что шаблон регулярного выражения не соответствует чему-либо в моей строке endp (почему у него есть 4 Nones? 1 для каждого ключевого слова, но для чего 4-го?). Я проверил свою конечную точку (регулярное выражение и по той же строке) с помощью валидатора регулярных выражений, мне кажется, что это хорошо. Я понимаю, что re.match должен получить совпадения с начала, поэтому я использовал метод re.search, так как documentation указывает, что он должен совпадать в любом месте строки.

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

+0

Не могли бы вы включить образец данных, которые вы пытаетесь сопоставить? – Faibbus

+0

Я предполагаю, что вы имеете в виду '([0-9] *) ((OK | BACK | X) *)', но я тоже хотел бы увидеть примеры того, что вы надеялись захватить, которые в настоящее время не работают. – tripleee

+0

Что-то вроде 'OKOKOKXXXXBACKBACK' или' 0123' будет соответствовать вашему текущему регулярному выражению. Если целью является захват повторяющихся ключевых слов как отдельных групп захвата, вам нужно столько групп захвата, сколько есть ключевых слов для захвата, или более реалистично захватить все и разбить его на отдельные ключевые слова из захваченной группы. Если число может быть не более одного и порядок определен, вы просто хотите '(ОК)? (BACK)? (X)?' – tripleee

ответ

0

Действительно, это немного удивительно, что поиск с * возвращает `Нет:

>>> re.search("(OK|BACK|X)*", u'/12OK').groups() 
(None,) 

Но это«правильно», так как * соответствует нулю или более, и любой шаблон соответствует ноль раз в любой строке, поэтому вы видите None.Поиск с + несколько решает его:

>>> re.search("(OK|BACK|X)+", u'/12OK').groups() 
('OK',) 

Но теперь, ища с этим рисунком в /12OKOK все еще находит только один матч, потому что + означает один или более, и это соответствует один раз при первом OK. Для того, чтобы найти все вхождения, нужно использовать re.findall:

>>> re.findall("(OK|BACK|X)", u'/12OKOK') 
['OK', 'OK'] 

С этими выводами, ваш код будет выглядеть следующим образом: (обратите внимание, что вам не нужно писать i[0] так i уже строка, если вы не хотите войти только первый символ строки):

import re 

endp = endp.encode('ASCII', 'ignore') 
match = re.search(r"([0-9]+)", str(endp)) 
if match: 
    n = match.groups() 
    logging.info('nums: ' + str(n)) 

match = re.findall(r"(OK|BACK|X)", str(endp), re.I) 
for i in match: 
    logging.info('str: ' + str(i)) 
+0

спасибо, это решило мою проблему – pszent

0

Если вы хотите совместить хотя бы одну из групп, используйте + вместо *.

>>> endp = '/12OK' 
>>> match = re.search(r"((OK)|(BACK)|(X))+", str(endp), re.I) 
>>> if match: 
...  s1 = match.groups() 
...  for i in s1: 
...   print s1 
... 
('OK', 'OK', None, None) 
>>> endp = '/12X' 
>>> match = re.search(r"((OK)|(BACK)|(X))+", str(endp), re.I) 
>>> match.groups() 
('X', None, None, 'X') 

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

0

"((OK) | (BACK) | (X)) *" будет искать OK или BACK или X, 0 или более раз. Обратите внимание, что значение * означает 0 или больше, не более 0. Вышеприведенное выражение должно иметь + в конце, а не * как +, означает 1 или больше.

+0

Этого недостаточно для решения проблемы OP, хотя мне непонятно, что именно * они ищут. '(OK | BACK | X) +' будет простым и идиоматическим способом делать то, что вы предлагаете. – tripleee

+0

Я не обязательно ожидаю этих ключевых слов, я хочу оставить возможность доступа к конечной точке только с номерами – pszent

0

Я думаю, что у вас есть два разных вопроса, и их пересечение вызывает больше путаницы, чем любой из них может вызвать сами по себе.

Первая проблема заключается в том, что вы используете повторяющиеся группы. Библиотека re Python не может захватывать несколько совпадений, когда группа повторяется. Совпадение с рисунком, как (X)+, против 'XXXX' приведет к захвату только одного 'X' в первой группе, хотя вся строка будет сопоставлена. regex library (который не входит в стандартную библиотеку) может выполнять несколько захватов, хотя я не уверен в точности требуемых команд.

Вторая проблема заключается в использовании оператора повторения * в вашем шаблоне. Образец, который вы показываете в верхней части вопроса, будет соответствовать пустой строке. Очевидно, что ни один из gropus не захватит что-либо в этой ситуации (что может быть, поэтому вы видите много результатов None в ваших результатах). Вероятно, вам необходимо изменить свой шаблон, чтобы он требовал некоторого минимального количества действительного текста для подсчета в качестве соответствия. Использование + вместо * может быть одним из решений, но мне непонятно, с чем именно вы хотите сопоставлять, поэтому я не могу предложить конкретный шаблон.

Смежные вопросы