- Редактировать - В текущих ответах есть несколько полезных идей, но мне нужно что-то более полное, что я могу на 100% понять и использовать повторно; поэтому я назначил награду. Также идеи, которые работают везде, для меня лучше, чем нестандартный синтаксис, например\K
Этот вопрос касается того, как я могу сопоставить шаблон, кроме некоторых ситуаций s1 s2 s3. Я привожу конкретный пример, чтобы показать, что я имею в виду, но предпочитаю общий ответ, который я могу понять на 100%, чтобы я мог повторно использовать его в других ситуациях.
пример
Я хочу сопоставить пять цифр, используя, \b\d{5}\b
но не в трех ситуациях s1 s2 s3:
s1: Не в строке, которая заканчивается точкой, как в этом предложении.
s2: нигде внутри парен.
s3: Не внутри блока, который начинается if(
и заканчивается на//endif
Я знаю, как решить любой из s1 s2 s3 с просмотром вперед и назад, особенно в C # lookbehind или \K
в PHP.
Например
s1 (?m)(?!\d+.*?\.$)\d+
s3 с обратным просмотром C # (?<!if\(\D*(?=\d+.*?//endif))\b\d+\b
s3 с PHP \ K (?:(?:if\(.*?//endif)\D*)*\K\d+
Но сочетание условий заставляет мою голову взорваться. Еще более плохая новость в том, что мне может потребоваться добавить другие условия s4 s5 в другое время.
Хорошая новость в том, что мне все равно, буду ли я обрабатывать файлы с помощью наиболее распространенных языков, таких как PHP, C #, Python или стиральной машины моего соседа. :) Я в значительной степени новичок в Python и Java, но мне интересно узнать, есть ли у него решение.
Итак, я пришел сюда, чтобы узнать, не придумает ли кто-нибудь гибкий рецепт.
Подсказки - это нормально: вам не нужно давать мне полный код. :)
Спасибо.
\K
нет специального синтаксиса php. Пожалуйста, уточните и поясните, что вы хотите сказать. Если вы хотите сказать нам, что вам не нужно «сложное» решение, вы должны сказать, что для вас сложно и почему."if("
open paren был закрыт не с помощью")"
, а с помощью"//endif"
:? И если для s3 вы действительно имели в виду, что предложение if должно быть закрыто с помощью:,"//endif)"
то требование s3 является подмножеством s2.especially in C# lookbehind or \K in PHP
... Но C # lookbehind не только C #, это .NET, так что вы тоже можете жаловаться Я говорю C #, а не .NET :) И в ответ я говорю Ruby, а не Onigurama, это тоже плохо ... Есть ли другой язык, использующий PCRE? Не говоря уже о Notepad ++ или серверных инструментах, это вопрос об использовании функции на языке, я надеюсь, что объясню и извиняюсь, если это выглядит неправильно,Ответы:
Ганс, я клюну и дополню свой предыдущий ответ. Вы сказали, что хотите «чего-то более полного», поэтому я надеюсь, что вы не будете возражать против длинного ответа - просто пытаетесь угодить. Начнем с некоторой предыстории.
Во-первых, это отличный вопрос. Часто возникают вопросы о сопоставлении определенных шаблонов, за исключением определенных контекстов (например, внутри блока кода или внутри скобок). Эти вопросы часто приводят к довольно неудобным решениям. Так что ваш вопрос о множественных контекстах - особая проблема.
Сюрприз
Удивительно, но существует по крайней мере одно эффективное решение, которое является общим, простым в реализации и приятным в обслуживании. Он работает со всеми разновидностями регулярных выражений, которые позволяют вам проверять группы захвата в вашем коде. И он отвечает на ряд общих вопросов, которые на первый взгляд могут показаться отличными от вашего: «сопоставить все, кроме пончиков», «заменить все, кроме ...», «сопоставить все слова, кроме тех, что в черном списке моей мамы», «игнорировать теги "," соответствует температуре, если не выделено курсивом "...
К сожалению, этот метод малоизвестен: по моим оценкам, из двадцати SO-вопросов, которые могли бы его использовать, только один имеет один ответ, в котором он упоминается, что означает, может быть, один из пятидесяти или шестидесяти ответов. Смотрите мой обмен с Коби в комментариях. Этот метод подробно описан в этой статье, в которой он (оптимистично) назван «лучшим трюком с регулярными выражениями». Не вдаваясь в подробности, я постараюсь дать вам четкое представление о том, как работает эта техника. Для получения более подробной информации и примеров кода на разных языках я рекомендую вам обратиться к этому ресурсу.
Наиболее известная вариация
Существует вариант использования синтаксиса, специфичного для Perl и PHP, который выполняет то же самое. Вы увидите его на SO в руках регулярных выражений мастеров , таких как CasimiretHippolyte и Хамза . Я расскажу вам больше об этом ниже, но я сосредоточусь здесь на общем решении, которое работает со всеми разновидностями регулярных выражений (при условии, что вы можете проверять группы захвата в своем коде).
Ключевой факт
Фактически, уловка состоит в том, чтобы сопоставить различные контексты, которые нам не нужны (объединяя эти контексты в цепочку с помощью
|
ИЛИ / чередования), чтобы «нейтрализовать их». После сопоставления всех нежелательных контекстов последняя часть чередования соответствует тому, что мы действительно хотим, и фиксирует это в Группе 1.Общий рецепт
Это будет совпадение
Not_this_context
, но в некотором смысле совпадение попадет в мусорное ведро, потому что мы не будем смотреть на общие совпадения: мы будем смотреть только на захваты группы 1.В вашем случае, игнорируя ваши цифры и три контекста, мы можем:
Обратите внимание: поскольку мы на самом деле сопоставляем s1, s2 и s3 вместо того, чтобы пытаться избежать их с помощью поиска, отдельные выражения для s1, s2 и s3 могут оставаться ясными как день. (Это подвыражения по обе стороны от a
|
)Все выражение можно записать так:
Посмотрите эту демонстрацию (но сосредоточьтесь на группах захвата в нижней правой панели.)
Если вы мысленно попытаетесь разделить это регулярное выражение по каждому
|
разделителю, на самом деле это будет всего лишь серия из четырех очень простых выражений.Это особенно хорошо читается для вкусов, которые поддерживают свободный интервал.
Это исключительно легко читать и поддерживать.
Расширение регулярного выражения
Если вы хотите игнорировать больше ситуаций s4 и s5, вы добавляете их в большем количестве слева:
Как это работает?
Нежелательные контексты добавляются в список альтернатив слева: они будут совпадать, но эти общие совпадения никогда не проверяются, поэтому их сопоставление - это способ поместить их в «мусорное ведро».
Однако желаемый контент сохраняется в Группу 1. Затем необходимо программно проверить, установлена ли Группа 1 и не пуста. Это тривиальная задача программирования (и позже мы поговорим о том, как это делается), особенно с учетом того, что она оставляет вам простое регулярное выражение, которое вы можете сразу понять и при необходимости изменить или расширить.
Я не всегда являюсь поклонником визуализаций, но эта хорошо показывает, насколько прост метод. Каждая «строка» соответствует потенциальному совпадению, но только нижняя строка попадает в группу 1.
Демо Debuggex
Вариант Perl / PCRE
В отличие от общего решения, приведенного выше, существует вариант для Perl и PCRE, который часто встречается в SO, по крайней мере, в руках богов регулярных выражений, таких как @CasimiretHippolyte и @HamZa. Это:
В твоем случае:
Этот вариант немного проще в использовании, потому что контент, сопоставленный в контекстах s1, s2 и s3, просто пропускается, поэтому вам не нужно проверять захваты Группы 1 (обратите внимание, что скобки исчезли). Матчи содержат только
whatYouWant
Обратите внимание , что
(*F)
,(*FAIL)
и(?!)
все то же самое. Если вы хотите быть более непонятным, вы можете использовать(*SKIP)(?!)
демо для этой версии
Приложения
Вот некоторые общие проблемы, которые часто можно легко решить с помощью этого метода. Вы заметите, что при выборе слова некоторые из этих проблем могут казаться разными, хотя на самом деле они практически идентичны.
<a stuff...>...</a>
?<i>
тега или фрагмента javascript (дополнительные условия)?Как запрограммировать захват группы 1
Вы не сделали этого в отношении кода, но для завершения ... Код для проверки Группы 1, очевидно, будет зависеть от выбранного вами языка. Во всяком случае, он не должен добавлять больше пары строк в код, который вы будете использовать для проверки совпадений.
Если вы сомневаетесь, я рекомендую вам взглянуть на раздел примеров кода в упомянутой ранее статье, в котором представлен код для нескольких языков.
Альтернативы
В зависимости от сложности вопроса и используемого механизма регулярных выражений существует несколько альтернатив. Вот два, которые могут применяться в большинстве ситуаций, включая несколько условий. На мой взгляд, ни один из них не так привлекателен, как
s1|s2|s3|(whatYouWant)
рецепт, хотя бы потому, что ясность всегда побеждает.1. Замените, затем сопоставьте.
Хорошее решение, которое кажется хакерским, но хорошо работает во многих средах, - это работа в два этапа. Первое регулярное выражение нейтрализует контекст, который вы хотите игнорировать, заменяя потенциально конфликтующие строки. Если вы хотите только сопоставить, вы можете заменить его пустой строкой, а затем выполнить сопоставление на втором этапе. Если вы хотите заменить, вы можете сначала заменить строки, которые нужно игнорировать, чем-то особенным, например, окружить ваши цифры цепочкой фиксированной ширины
@@@
. После этой замены вы можете заменить то, что действительно хотели, тогда вам придется вернуть свои отличительные@@@
строки.2. Обращения.
Ваш исходный пост показал, что вы понимаете, как исключить одно условие с помощью поиска. Вы сказали, что C # отлично подходит для этого, и вы правы, но это не единственный вариант. Варианты регулярных выражений .NET, найденные, например, в C #, VB.NET и Visual C ++, а также все еще экспериментальный
regex
модуль для заменыre
в Python - единственные два известных мне движка, которые поддерживают просмотр назад с бесконечной шириной. С помощью этих инструментов одно условие в одном просмотре назад может позаботиться о просмотре не только назад, но и в соответствии с совпадением и за его пределами, избегая необходимости согласовывать с просмотром вперед. Еще условия? Больше поисков.Переработав регулярное выражение, которое у вас было для s3 в C #, весь шаблон будет выглядеть так.
Но теперь вы знаете, что я не рекомендую это, верно?
Удаления
@HamZa и @Jerry предложили мне упомянуть дополнительный трюк для случаев, когда вы стремитесь просто удалить
WhatYouWant
. Вы помните, что рецепт совпаденияWhatYouWant
( включение его в группу 1) былs1|s2|s3|(WhatYouWant)
правильным? Чтобы удалить все экземплярыWhatYouWant
, вы измените регулярное выражение наДля строки замены вы используете
$1
. Здесь происходит то, что для каждогоs1|s2|s3
сопоставленного$1
экземпляра замена заменяет этот экземпляр самим собой (на который ссылается$1
). С другой стороны, приWhatYouWant
сопоставлении она заменяется пустой группой и ничем другим - и поэтому удаляется. Посмотрите эту демонстрацию , спасибо @HamZa и @Jerry за предложение этого замечательного дополнения.Замены
Это подводит нас к заменам, о которых я кратко коснусь.
(*SKIP)(*F)
вариант, упомянутый выше, чтобы точно соответствовать тому, что вы хотите, и выполните прямую замену.Радоваться, веселиться!
Нет, подождите, это еще не все!
Ах, нет, я приберегу это для своих мемуаров в двадцати томах, которые выйдут следующей весной.
источник
Tarzan
, но не в двойных кавычках./no|no|(yes)/
Регулярное выражение : trick будет выглядеть примерно так:/"[^"]*"|Tarzan/
(игнорируя экранированные символы). Это будет работать во многих случаях, но не может полностью , когда применяется к следующему уважительной тексту JavaScript:var bug1 = 'One " quote here. Should match this Tarzan'; var bug2 = "Should not match this Tarzan";
. Уловка Рекса работает только тогда, когда ВСЕ возможные структуры совпадают - другими словами, вам нужно полностью проанализировать текст, чтобы гарантировать 100% точность.var bug1 = /"[^"]*"|(Tarzan)/gi;
и имел бы тот же эффект (и этот второй пример, конечно, не является пограничным). Я мог бы привести еще много примеров, когда этот метод не работает надежно.(?<!\\)"(?:\\"|[^"\r\n])*+"
команду «Не тяните за собой большие пушки, если у вас нет причины». Принцип решения остается в силе. Если мы не можем выразить шаблон для левой стороны, это другая история, нам нужно другое решение. Но решение делает то, что рекламирует.Выполните три разных сопоставления и обработайте комбинацию из трех ситуаций, используя условную логику в программе. Вам не нужно обрабатывать все в одном гигантском регулярном выражении.
РЕДАКТИРОВАТЬ: позвольте мне немного расширить, потому что вопрос стал более интересным :-)
Общая идея, которую вы здесь пытаетесь уловить, - это сопоставление с определенным шаблоном регулярного выражения, но не тогда, когда в тестовой строке присутствуют определенные другие (может быть любое число) шаблоны. К счастью, вы можете воспользоваться преимуществами своего языка программирования: используйте простые регулярные выражения и просто используйте составные условные выражения. Лучшей практикой было бы зафиксировать эту идею в повторно используемом компоненте, поэтому давайте создадим класс и метод, которые его реализуют:
Итак, выше мы настраиваем строку поиска (пять цифр), несколько строк исключения (ваши s1 , s2 и s3 ), а затем пытаемся сопоставить несколько тестовых строк. Напечатанные результаты должны быть такими, как показано в комментариях рядом с каждой тестовой строкой.
источник
Ваше требование, чтобы это не было внутри парен, невозможно удовлетворить во всех случаях. А именно, если вы каким-то образом можете найти
(
слева и)
справа, это не всегда означает, что вы находитесь внутри скобок. Например.(....) + 55555 + (.....)
- не внутри скобок еще есть(
и)
слева и справаТеперь вы можете считать себя умным и искать
(
слева только в том случае, если вы не встречали)
раньше, и наоборот, справа. В этом случае это не сработает:((.....) + 55555 + (.....))
- внутри паренсы, хотя есть закрывающие)
и(
слева, и справа.С помощью регулярного выражения невозможно определить, находитесь ли вы внутри паренсов, так как регулярное выражение не может подсчитать, сколько паренов было открыто и сколько закрыто.
Рассмотрим более простую задачу: используя регулярное выражение, выяснить, все ли (возможно, вложенные) скобки в строке закрыты, то есть для каждого, что
(
вам нужно найти)
. Вы обнаружите, что это невозможно решить, и если вы не можете решить это с помощью регулярного выражения, тогда вы не сможете выяснить, находится ли слово внутри скобок для всех случаев, поскольку вы не можете определить какую-либо позицию в строке, если все предыдущие(
имеют соответствующий)
.источник
Ганс, если ты не против, я пользовался стиральной машиной твоего соседа под названием perl :)
Отредактировано: ниже псевдокода:
Учитывая файл input.txt:
И скрипт validator.pl:
Исполнение:
источник
Не уверен, поможет ли это вам или нет, но я предлагаю решение, учитывая следующие предположения:
Однако я рассмотрел также следующее -
if(
блоки.Хорошо, вот решение -
Я использовал C # и вместе с ним MEF (Microsoft Extensibility Framework) для реализации настраиваемых парсеров. Идея состоит в том, чтобы использовать один синтаксический анализатор для синтаксического анализа и список настраиваемых классов валидатора для проверки строки и возврата истинного или ложного значения на основе проверки. Затем вы можете добавить или удалить любой валидатор в любое время или добавить новые, если хотите. До сих пор я уже реализовал для S1, S2 и S3, о которых вы упомянули, проверьте классы в пункте 3. Вы должны добавить классы для s4, s5, если вам понадобятся в будущем.
Сначала создайте интерфейсы -
Затем идет программа для чтения и проверки файлов -
Затем идет реализация отдельных чекеров, имена классов говорят сами за себя, поэтому я не думаю, что им нужно больше описаний.
Программа -
Для тестирования я взял образец файла @Tiago, в
Test.txt
котором были следующие строки:Дает результат -
Не знаю, поможет ли это вам или нет, я весело провел время, играя с этим .... :)
Самое приятное в этом то, что для добавления нового условия все, что вам нужно сделать, это предоставить реализацию
IPatternMatcher
, оно будет автоматически вызвано и, таким образом, будет проверяться.источник
То же, что и @ zx81,
(*SKIP)(*F)
но с использованием утверждения отрицательного просмотра вперед .ДЕМО
В python я бы легко сделал это,
Вывод:
источник