Как построить итератор на основе tokenizing регулярных выражений в Python

голоса
-2

Я основывая этот вопрос на ответ , который я дал этому другой СЦ вопрос , который был моей конкретной попыткой на основе итератора tokenizing регулярных выражений с использованием парного рецепт итератора more_itertools'S.

Ниже мой код взят из этого ответа:

from more_itertools import pairwise
import re

string = dasdha hasud hasuid hsuia dhsuai dhasiu dhaui d
# split according to the given delimiter including segments beginning at the beginning and ending at the end
for prev, curr in pairwise(re.finditer(r^|[ ]+|$, string)):
    print(string[prev.end(): curr.start()])  # originally I yield here

Затем я заметил , что если строка начинается или заканчивается с разделителями (то есть string = dasdha hasud hasuid hsuia dhsuai dhasiu dhaui d ) , то токенизатор будет печатать пустые строки (это на самом деле дополнительные совпадения начала строки и конец строки) в начале и в конце своего списка лексем выходов таким образом , чтобы это исправить Я попытался следующие (довольно уродливые) попытки других регулярных выражений:

  1. «(?: ^ | [] | $) +» - это , кажется , довольно просто и как она должна работать , но это не делает (а также , кажется, ведет себя дико отличается от других регулярных выражений двигателей) по какой - то причине он не будет строить одиночный матч от начала струны и ограничителей после него , строки начать как - то потребляет символ после него! (это также , где я вижу дивергенции от других двигателей, является ли это BUG? или у него есть что - то делать с помощью специальных символов , не являющихся телесных и или (|? оператора) в Python , что я не знаю), это решение также ничего не сделал для двойного матча , содержащего конец струны, когда она соответствует разделителей , а затем дал еще один матч на конец строки ($) сам характер.

  2. «(: [] | $ | ^?) +» - Положив разделители первого фактически решает одну из проблем, раскол в начале не содержит начало строки (но я все равно слишком много о том, что в любом случае , так как я «заинтересован в самих лексемах), он также соответствует началу строки , когда нет разделителей в начале строки , но строка окончание все еще остается проблема.

  3. «(^ [] *) | ([] * $) | ([] +)» - Это последняя попытка получила строка начать быть частью первого матча (который не был на самом деле , что большая проблема в первую место) , но попробовать , как я мог бы я не мог избавиться от разделителя + конца , а затем проблем соответствия разделителя (что дает дополнительную пустую строку), до сих пор, я показываю вам этот пример (с группировкой) , так как это показывает , что заканчивая специальный символ $ сопоставляется дважды, один раз с предыдущими разделителей и один раз сам по себе (2 группы 2 соответствий).

Мои вопросы:

  1. Почему я получаю такое странное поведение при попытке # 1
  2. Как решить конец строки вопроса?
  3. Могу ли я быть танком, т.е. есть простой способ решить эту проблему, что я слепо не хватает?
  4. помните , что решение не может изменить строку и должна произвести итерацию генератор , который итерирует на пространствах между маркерами и не сами лексемы (Эта последняя часть может показаться , что затруднит ответ излишне , так как в противном случае у меня есть простой ответ , но если вы должен знать ( и если вы не читайте дальше ) это часть большой структуры , я в здании , где этот метод , дающий наследуются по трубопроводу , который затем конструкты давали предложения из нее в различных моделях , которые используются для извлечения полей из пол структурированного классификатор управляемого сообщениями)
Задан 22/01/2018 в 17:11
источник пользователем
На других языках...                            


2 ответов

голоса
1

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

# match any number of consecutive non-delim chars
string = "  dasdha hasud hasuid hsuia dhsuai dhasiu dhaui d  "
delimiters = '\n\- '
regex = r'([^{0}]+)'.format(delimiters)
for match in re.finditer(regex, string):
    print(match.group(0))

вывод:

dasdha
hasud
hasuid
hsuia
dhsuai
dhasiu
dhaui
d
Ответил 22/01/2018 в 17:27
источник пользователем

голоса
2

В вас возникли проблемы обусловлены trickiness и недокументированные крайние случаи нулевой ширины спичек. Вы можете решить их с помощью отрицательных lookarounds явно указать Python не производить спичку ^или $если строка имеет разделители в начале или конце:

delimiter_re = r'[\n\- ]'     # newline, hyphen, or space
search_regex = r'''^(?!{0})   # string start with no delimiter
                   |          # or
                   {0}+       # sequence of delimiters (at least one)
                   |          # or
                   (?<!{0})$  # string end with no delimiter
                '''.format(delimiter_re)
search_pattern = re.compile(search_regex, re.VERBOSE)

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

Это может быть проще перебрать без разделителей последовательностей и использовать полученные спички, чтобы найти струнные компоненты, которые вы хотите:

token = re.compile(r'[^\n\- ]+')
previous_end = 0
for match in token.finditer(string):
    do_something_with(string[previous_end:match.start()])
    previous_end = match.end()
do_something_with(string[previous_end:])

Дополнительные матчи вы получали в конце строк были , потому что после согласования последовательности ограничителей в конце концов, движок регулярных выражений ищет соответствия в конце снова, и находит нулевую ширину матча за $.

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

Поведение , которое вы получали в начале строки для (?:^|...)+шаблона еще сложнее. Выполнение этого прямолинейно, двигатель будет выглядеть на матч за (?:^|...)в начале строки, найти ^, а затем искать другой матч, найти ^снова, а затем искать другой матч бесконечности. Там какая - то недокументированная обращение , которое останавливает его от идти вечно, и это обращение , как представляется , производить матч нулевой ширины, но я не знаю , что это обращение является.

Ответил 22/01/2018 в 18:41
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more