Извлечение фрагментов с помощью регулярного выражения PCRE - PullRequest
0 голосов
/ 22 июня 2009

Я работаю с длинными абзацами текста, которые можно искать с помощью MySQL и PHP. Я хотел бы иметь возможность находить и выделять только релевантные условия поиска и использовать регулярные выражения для их выделения.

Например, я хотел бы преобразовать абзац Lorem ipsum,

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud 
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor 
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur 
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est 
laborum.

во что-то подобное при поиске "dolor",

Lorem ipsum *dolor* sit amet ... labore et *dolor*e magna aliqua ... aute irure *dolor* in reprehenderit ... esse cillum *dolor*e eu fugiat ...

с двумя (или сколь угодно многими) словами до и после термина.

Пока у меня есть это

search  - .*?(\w+?\b\s){2}(dolor)(\w+?\b\s){2}.*?
replace - ... $1*$2*$3... 

но это не совсем работает; он находит только одно слово до и после (несмотря на {2}), завершается неудачно, когда строка поиска находится в начале или конце строки (или предложения), и не удаляет остаток абзаца после последнего найденного экземпляра строка поиска.

Какой лучший способ сделать это?

Спасибо!

Ответы [ 3 ]

1 голос
/ 22 июня 2009

Пара изменений:

((\w+\b\s*){2})(dolor)(\w*\s*(\w+\b\s*){2})

...$1*$3*$4...

Во-первых, множитель {2} должен содержаться в памяти в обоих случаях, чтобы вы запомнили оба слова. Это означает, что мы можем игнорировать $2 при повторном чтении ($5 теперь содержит последнее найденное слово).

Во-вторых, в случае «dolore» и всего, что связано с dolor \ w +, терминал «e» становится самостоятельным словом; чтобы соответствовать вашей спецификации выше, я добавил \ w * \ s *, чтобы перехватывать любые символы конца слова и терминальные пробелы в оставшейся части.

В противном случае, не жадный "?" Здесь char на самом деле не нужен, потому что вы уже указали \ b в конце своего \ w +, поэтому я тоже убрал их.

0 голосов
/ 22 июня 2009

Сбой в начале / конце, потому что вы указываете (или, по крайней мере, пытаетесь указать ...), что совпадение должно включать ровно два слова начального и конечного контекста. Если ваш «dolor» - первое слово, перед ним ничего нет, поэтому совпадение не получится. Изменение {2} на {0,2} должно исправить эту часть.

Еще одна вещь, которая сразу бросается в глаза, это использование \w+?\b\s. Вы, наверное, имеете в виду \w*\b\s. * означает «соответствовать нулю или более», что эквивалентно «по желанию соответствовать одному или нескольким», которые вы пытаетесь указать с помощью +?. Также обратите внимание, что, если вы не измените \s на \s+, произойдет сбой в словах, разделенных несколькими пробелами. Есть также потенциальные проблемы с пунктуацией или другими символами, которые не являются ни словом, ни пробелами.

В конце концов, я думаю, что регулярные выражения могут быть не лучшим подходом к тому, чего вы пытаетесь достичь, или, по крайней мере, сами по себе. Наиболее эффективный способ сделать это, вероятно, состоит в создании настраиваемого полнотекстового поиска с обратным индексом, содержащим текст слова, его позицию (чтобы вы могли получить их в правильном порядке) и выделенное слово в контексте ( так что вы можете просто объединить их вместе для вашего конечного результата).

Если это не вариант, я бы пошел на разбиение текста на массив слов, а затем просканировал бы это для вашего целевого слова. Это не только облегчит выполнение ваших требований к контексту, но я ожидаю, что оно также будет работать быстрее, чем решение с использованием регулярных выражений, поскольку это сильно уменьшит потенциальную потребность в возврате. (OTOH, тем не менее, выполнение двух проходов по тексту (первый проход, чтобы разделить его на массив слов, второй проход, чтобы сравнить каждое слово с вашими поисковыми терминами) может изменить ситуацию по-другому.)

0 голосов
/ 22 июня 2009

Относительно проблемы, что только одно слово соответствует:

Из документации PHP PCRE

Когда подшаблон захвата повторяется, полученное значение является подстрока, которая соответствует финалу итерации.

, например

String
"tweedledum tweedledee"

Regex
(tweedle[dume]{3}\s*)+

Captured value
tweedledee

Это регулярное выражение должно немного приблизить вас.

.*?(\w+\b\s*\w+\b\s*)?(dolor)(\w*\s*\w+\b\s*\w+\b)?.*?

Не работает для dolor в конце или в начале строки. Не обрабатывает не пробелы или не слова. Не решает проблему нескольких экземпляров dolor, следующих друг за другом (например, dolor dolor dolor). Не обрабатывается, когда слово «dolor» находится в «звене с двумя словами» (например, Lorem ipsum dolor amet dolor). Возможные другие особые случаи, о которых я сейчас не могу вспомнить, тоже бесполезны: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...