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

1

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

Я очистил данные из вики (для обучения), и я пытаюсь извлечь строки

a), которые начинаются с \wiki

б) которые не содержат :

Здесь текст:

/wiki/Template:Kevin_Bacon
/wiki/Category:Best_Miniseries_or_Television_Movie_Actor_Golden_Globe_winners
/wiki/Al_Pacino
/wiki/Paul_Giamatti
/wiki/Kevin_Costner
/wiki/Kevin_Costner
/wiki/Michael_Douglas
/wiki/Mark_Ruffalo
/wiki/Idris_Elba
/wiki/Bryan_Cranston
/wiki/Alexander_Skarsg%C3%A5rd
/wiki/Biblioteca_Nacional_de_Espa%C3%B1a
/wiki/Template:Kevin_Bacon
https://hy.wikipedia.org/wiki/%D5%94%D6%87%D5%AB%D5%B6_%D4%B2%D5%A5%D5%B5%D6%84%D5%B8%D5%B6

Вывод должен быть сгруппирован, т.е. я должен получить список (или кортеж) этих строк:

/wiki/Al_Pacino
/wiki/Paul_Giamatti
/wiki/Kevin_Costner
/wiki/Kevin_Costner
/wiki/Michael_Douglas
/wiki/Mark_Ruffalo
/wiki/Idris_Elba
/wiki/Bryan_Cranston
/wiki/Alexander_Skarsg%C3%A5rd
/wiki/Biblioteca_Nacional_de_Espa%C3%B1a

Вот мои попытки извлечь строки:

a) Использование негативного r^/wiki/.*(?!:).* : идея состоит в том, чтобы не выбирать строку, за которой следует : r^/wiki/.*(?!:).* Однако выше код по-прежнему выбирает строки с помощью : ie /wiki/Template:Kevin_Bacon

b) ^/wiki/.*[^:].* регулярное выражение, чтобы не выбирать : ^/wiki/.*[^:].* Однако выше код по-прежнему выбирает строки с помощью : ie /wiki/Template:Kevin_Bacon

c) Использовать квантификатор, чтобы указать, что : должно происходить нулевое время ^/wiki/.*:{0}.*$ Однако выше код по-прежнему выбирает строки с помощью : ie /wiki/Template:Kevin_Bacon

У меня есть два вопроса:

a) Мне очень нравится regex. Может кто-нибудь объяснить, что неправильно с помощью вышеуказанных попыток?

б) Как я могу решить проблему, используя вышеуказанные подходы?

Я собираюсь использовать модуль regex в python. В соответствии с рекомендациями SO я пытался отлаживать regex на regex101 сайте regex101. Здесь ссылка: https://regex101.com/r/Wt40Cz/1

Я искренне ценю любую помощь. Заранее спасибо.

  • 2
    Попробуйте ^\/wiki\/[^:]+?$
  • 0
    Большое спасибо. Не могли бы вы объяснить, почему вы удалили .* До и после «исключения двоеточия», то есть [^:] . Я пытаюсь выучить логику. Заранее спасибо.
Показать ещё 4 комментария
Теги:

2 ответа

2
Лучший ответ

Ваше регулярное выражение неверно.

^/wiki/.*[^:].*

анализируется следующим образом:

  • ^: соответствие началу строки
  • /wiki/: соответствие буквенной последовательности /wiki/
  • .*: совпадение нуля или более любого символа
  • [^:]: сопоставить все, что не является :
  • .*: совпадение нуля или более любого символа

Так что

  1. соответствует началу строки (ok)
  2. соответствует литеральному /wiki/ (ok)
  3. соответствует всей остальной части линии (uh-oh)
  4. отбрасывает символ и сопоставляет "ничего, что не является : ", если последний символ не является : (хм...)
  5. ничего не соответствует, т.е. ноль или более любого символа

Поэтому ваше регулярное выражение заканчивается совпадением всей строки из-за .*, Даже не проверяя : кроме как в конце.

Теперь посмотрим, что делает правильное выражение

^\/wiki\/[^:]+$
  • ^: соответствие началу строки
  • /wiki/: соответствие буквенной последовательности /wiki/
  • [^:]+: сопоставить одно или несколько из ничего, что не является :
  • $: совпадение с концом строки

    1. соответствует началу строки (ok)
    2. соответствует литеральному /wiki/ (ok)
    3. соответствует всей остальной части строки, если она не содержит : в этом случае она не выполняется
    4. соответствует концу строки

Надеюсь, это поможет вам лучше разобраться. Я настоятельно рекомендую https://www.regex101.com для создания и тестирования регулярных выражений (он имеет режим регулярного выражения, совместимый с Python), поскольку он также включает в себя объяснение того, что движок регулярного выражения делает шаг за шагом.

Изменение: чтобы ответить на второй вопрос, я не вижу другого разумного способа построения этого выражения. Не используйте lookaheads или quantifiers, что не для этого.

  • 0
    большое спасибо. Я потратил смущающее количество часов на это. У меня есть одно уточнение: не правда ли, что .* Будет соответствовать 0 or more символам, пока не достигнет [^:] , когда он вернется назад и вообще исключит эту строку? Я не понял вашу пулю № 3. Если то, что вы сказали, верно, то не следует выбирать строки с помощью : Из ссылки на regex101 я разместил, этого не происходит. Буду признателен за ваши мысли.
  • 1
    @watchtower это соответствует всей остальной части строки, потому что это жадно соответствует «ноль или более символов». Это явно остальная часть линии! Он пытается вернуться назад только после того, как не может сравниться ни с чем другим. Смотрите здесь .
Показать ещё 2 комментария
1

Попробуйте regex ^\/wiki\/[^:]*?$

Он будет соответствовать строке, начинающейся с /wiki/ а затем этой [^:]*? будет соответствовать символам без : до конца $

В вашем регулярном выражении ^/wiki/.*[^:].*$ было два .* Так что : будет сбежать с любым из .*.So, [^:]* будет достаточно, чтобы захватить все

Regex

Ещё вопросы

Сообщество Overcoder
Наверх
Меню