Python, регулярное выражение отрицательного поведения при поиске сзади

#python #regex

#python #регулярное выражение

Вопрос:

У меня есть обычный эксперимент, который должен находить до 10 слов в строке. То есть оно должно включать слово, непосредственно предшествующее переводу строки, но не слова после перевода строки. Я использую отрицательный внешний вид с » n».

 a = re.compile(r"((w) [s /]){0,10}(?<!n)")
r = a.search("THe car is parked in the garagenBut the sun is shining hot.")
  

Когда я выполняю это регулярное выражение и вызываю метод r.group(), я получаю обратно все предложение, кроме последнего слова, которое содержит точку. Я ожидал увидеть только полную строку, предшествующую новой строке. То есть «машина припаркована в гараже n».
В чем ошибка, которую я совершаю здесь с отрицательным взглядом сзади …?

Комментарии:

1. Можете ли вы отредактировать свой вопрос, включив в него еще несколько примеров? Приведенное ниже обсуждение сбило меня с толку относительно того, чего именно вы пытаетесь достичь.

Ответ №1:

Я не знаю, зачем вам использовать отрицательный обзор. Вы говорите, что хотите, чтобы перед переводом строки было не более 10 слов. Приведенное ниже регулярное выражение должно работать. Он использует положительный просмотр, чтобы гарантировать, что после слов есть перевод строки. Также при поиске слов используйте `b w b` вместо того, что вы использовали.

 /(bw b)*(?=.*\n)/
  

Python :

 result = re.findall(r"(bw b)*(?=.*\n)", subject)
  

Объяснение :

 # (bw b)*(?=.*\n)
# 
# Match the regular expression below and capture its match into backreference number 1 «(bw b)*»
#    Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
#    Note: You repeated the capturing group itself.  The group will capture only the last iteration.  Put a capturing group around the repeated group to capture all iterations. «*»
#    Assert position at a word boundary «b»
#    Match a single character that is a “word character” (letters, digits, etc.) «w »
#       Between one and unlimited times, as many times as possible, giving back as needed (greedy) « »
#    Assert position at a word boundary «b»
# Assert that the regex below can be matched, starting at this position (positive lookahead) «(?=.*\n)»
#    Match any single character that is not a line break character «.*»
#       Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
#    Match the character “” literally «\»
#    Match the character “n” literally «n»
  

Возможно, вы также захотите учесть тот факт, что в вашей строке не может быть n.

Комментарии:

1. На самом деле я хотел бы найти до десяти слов с начала строки. Проблема в том, что в некоторых случаях у меня может быть меньше слов в строке и есть новая строка ( n) непосредственно после последнего слова (например …hot n). В этом случае я хочу также включить последнее слово.

2. @user963386 Я в замешательстве. Не могли бы вы, пожалуйста, опубликовать примеры входных и выходных данных, чтобы вы могли прояснить свою проблему?

3. Пример 1: «Я за рулем, завтра солнце жаркое, я буду ловить рыбу» В этом случае я хотел бы найти «Завтра солнце горячее»

4. @user963386 Пожалуйста, приведите примеры в вашем вопросе.

5. Пример 1: «Я за рулем, завтра солнце жаркое, я буду ловить рыбу» В этом случае я хотел бы найти «Завтра солнце жаркое» Пример 2: «текст очень длинный, очень длинный, очень длинный, да, да «. В этом случае я хотел бы найти первые десять слов «текст — это «текст очень длинный, очень длинный, очень длинный, да» (первые 10 слов).

Ответ №2:

Если я вас правильно понял, вы хотите прочитать до 10 слов или первую новую строку, в зависимости от того, что будет первым:

 ((?:(?<!n)w b[s.]*){0,10})
  

При этом используется отрицательный поиск сзади, но непосредственно перед совпадением слов, поэтому блокируется получение любого слова после перевода строки.

Потребуется некоторая настройка из-за несовершенного ввода, но это только начало.

Ответ №3:

Для этой задачи есть привязка, $ позволяющая найти конец строки, и вместе с модификатором re.MULTILINE / re.M она найдет конец строки. Таким образом, в итоге вы получите что-то вроде этого

 (bw b[.s /]{0,2}){0,10}$
  

Смотрите это здесь, в Regexr

b — это граница слова. Я включил [.s /]{0,2} для соответствия точку, за которой следует пробел в моем примере. Если вам не нужны точки, вам нужно сделать эту часть по крайней мере необязательной, как это [s /]? иначе она будет отсутствовать в последнем слове, и тогда s будет соответствовать n .

Обновление / Идея 2

Хорошо, возможно, я неправильно понял ваш вопрос с моим первым решением.

Если вы просто хотите не сопоставлять новую строку и продолжить во второй строке, то просто не разрешайте это. Проблема в том, что новой строке соответствует s в вашем символьном классе. s Это класс для пробелов, который включает также символы новой строки r и n

У вас уже есть пробел в классе, тогда просто замените его s на t на случай, если вы хотите разрешить tab, и тогда все будет в порядке без поиска сзади. И, конечно, сделайте класс character необязательным, иначе последнее слово также не будет сопоставлено.

 ((w) [t /]?){0,10}
  

Смотрите это здесь, в Regexr

Комментарии:

1. Разве это не всегда будет возвращать последние десять слов во входных данных?

2. @N3dst4 вместе с многострочным модификатором вернет последние 10 слов перед разрывом строки.

3. Спасибо Stema. Однако я не понимаю, почему внешний вид (отрицательный) не работает, чтобы исключить «новую строку». s будет включать новую строку, но отрицательный просмотр для новой строки должен «исключить» новую строку.

4. @user963386 потому что ваш поиск сзади находится в неправильном положении. Он оглядывается назад со своей позиции, это последняя часть в вашем регулярном выражении, поэтому она будет соответствовать всему, что вы разрешаете, а затем проверяет, является ли последний совпадающий символ n , см. Ответ @N3dst4, у него есть поиск сзади в правильном месте.

5. Возможно, я неправильно понял «отрицательный взгляд сзади». Я думал, что «отрицательный взгляд сзади», размещенный в конце шаблона, должен был посмотреть на «совпадение» и отклонить его, если последний символ в совпадении равен n. Вы имеете в виду, что если я сопоставил n в своем совпадении, n будет использовано, и «отрицательный взгляд сзади» этого не увидит?

Ответ №4:

Я думаю, вам вообще не следует использовать lookbehind. Если вы хотите сопоставить до десяти слов, не включая новую строку, попробуйте это:

 S (?:[ t] S ){0,9}
  

Слово определяется здесь как один или несколько символов, не содержащих пробелов, которые включают точки, апострофы и другие знаки препинания в предложении, а также буквы. Если вы знаете, что текст, который вы сопоставляете, является обычной прозой, нет смысла ограничивать себя w , который на самом деле не предназначен для сопоставления со словами на естественном языке в любом случае.

После первого слова оно повторно сопоставляет один или несколько горизонтальных пробельных символов (пробел или ТАБУЛЯЦИЯ), за которыми следует другое слово, максимум десять слов. Если он встречает новую строку перед десятым словом, он просто прекращает сопоставление в этот момент. Нет необходимости упоминать новые строки в regex вообще.