Следование за предыдущим вопросом, в котором я спросил:
Как я могу использовать регулярное выражение для соответствия тексту, который является между двумя строками, где те две строки самостоятельно включаются две других строки с какой-либо суммой текста между внутренними и внешними строками включения?
Я получил этот ответ:
/outer-start.*?inner-start(.*?)inner-end.*?outer-end/
Я теперь хотел бы знать, как исключить определенные строки из текста между внешними строками включения и внутренними строками включения.
Например, если у меня есть этот текст:
внешний - запускаются, некоторый внутренний текст - запускают text-that-i-want внутренний конец еще некоторый текстовый внешний конец
Я хотел бы, 'чтобы некоторый текст' и 'еще некоторый текст' не содержали 'нежелательное' слово.
Другими словами, это в порядке:
внешний - запускаются, некоторый требуемый внутренний текст - запускают text-that-i-want внутренний конец еще некоторый требуемый текстовый внешний конец
Но это не в порядке:
внешний - запускаются, некоторый внутренний ненужный текст - запускают text-that-i-want внутренний конец еще некоторый внешний конец ненужного текста
Или объяснить далее, выражение между внешними и внутренними разделителями в предыдущем ответе выше должно исключить 'нежелательное' слово.
Действительно ли это легко соответствовать использованию regexes?
Замените первую и последнюю (но не среднюю) .*?
на (?:(?!нежелательно))*?
. (Где (?:...)
является не захватывающей группой, а (?!...)
- отрицательной.)
Однако, это быстро заканчивается угловыми случаями и предостережениями в любом реальном (вместо примера) использовании, и если вы спросите о том, что вы на самом деле делаете (с реальными примерами, даже если они упрощены, вместо выдуманных примеров), вы, скорее всего, получите лучшие ответы.
[112207].Попробуйте заменить последний .*? на другой: (?!(.*нежелательный текст.*))
Сработало?
Это не так просто сделать с помощью простых регексов, но некоторые системы, такие как Perl, имеют расширения, которые облегчают эту задачу. Один из способов - использовать отрицательное утверждение:
/outer-start(?:u(?!nwanted)|[^u])*?inner-start(.*?)inner-end.*?outer-end/
Ключ состоит в том, чтобы разделить "ненужное" на ("u", за которым не следует "nwanted") или (не "u"). Это позволит шаблону продвигаться вперед, но все равно найдет и отвергнет все "нежелательные" строки.
Люди могут начать ненавидеть ваш код, если вы сделаете большую часть этого. ;)
. Вы можете заменить .*?
на
([^u]|u[^n]|un[^w]|unw[^a]|unwa[^n]|unwan[^t]|unwant[^e]|unwante[^d])*?
Это решение в "чистом" регексе; язык, который вы используете, может позволить вам использовать более элегантную конструкцию.
.Лучший вопрос, который можно задать себе, чем "как это сделать с регулярными выражениями?" - это "как это решить эту проблему? Другими словами, не зацикливайтесь на попытках решить большую проблему с регулярными выражениями. Если вы можете решить половину проблемы с регулярными выражениями, сделайте это, а вторую половину решите другим регулярным выражением или другой техникой.
Например, пропустите данные, получив все совпадения, игнорируя ненужный текст (читать: получите результаты как с ненужным текстом, так и без него). Затем пропустите сокращенный набор данных и удалите те результаты, в которых есть нежелательный текст. Такое решение легче написать, проще понять и проще поддерживать с течением времени. И для любой проблемы, которую вам, скорее всего, придется решать при таком подходе, оно будет достаточно быстрым.