Мы извлекаем текст из файлов PDF, и очень часто результаты содержат искаженный текст. В частности, добавление пробелов между символами слова. например SEATTLE возвращается как S E A T T L E.
Есть ли выражение RegEx для preg_replace, которое может удалить любые пробелы в случае n количества односимвольных «слов»? В частности, удалить пробелы из любого вхождения строки, состоящей из более чем трех одиночных буквенных символов и разделенных пробелами?
Если погуглил какое-то время, но не могу даже представлять себе, как построить выражение. Как указано в комментарии, я не хочу, чтобы ВСЕ пробелы удалялись, но только тогда, когда встречается> 3 одиночных альфа-символа, например. Welcome to the Greater S E A T T L E area должен стать Welcome to the Greater SEATTLE area. Результат будет использоваться при полнотекстовом поиске, поэтому чувствительность к регистру не является проблемой.
Это выглядит многообещающе, но, как вы можете догадаться, RegEx для меня - это волшебство. Можете ли вы предоставить это выражение в качестве ответа в рабочем примере?






Вы можете использовать простой подход с preg_replace_callback. Сопоставьте пробелы '~\b[A-Za-z](?: [A-Za-z]){2,}\b~' и str_replace в анонимной функции:
$regex = '~\b[A-Za-z](?: [A-Za-z]){2,}\b~';
$result = preg_replace_callback($regex, function($m) {
return str_replace(" ", "", $m[0]);
}, $s);
См. демонстрация регулярного выражения.
Чтобы соответствовать только последовательностям заглавных букв, удалите a-z из шаблона:
$regex = '~\b[A-Z](?: [A-Z]){2,}\b~';
И еще: могут быть мягкие / жесткие пробелы, вкладки и другие пробелы. Затем используйте
$regex = '~\b[A-Za-z](?:\h[A-Za-z]){2,}\b~u';
^^ ^
Наконец, чтобы соответствовать любой букве Unicode, используйте \p{L} (чтобы соответствовать только прописным буквам, \p{Lu}) вместо [a-zA-Z]:
$regex = '~\b\p{L}(?:\h\p{L}){2,}\b~u';
Детали выкройки
\b - граница слова[A-Za-z] - одна буква(?: [A-Za-z]){2,} - 2 или более появления
- пробел (\h соответствует любым горизонтальным пробелам)[A-Za-z] - одна буква\b - граница словаКогда используется модификатор u, \h поддерживает Unicode.
СПАСИБО ... Ваш комментарий заработал после того, как удалил ~ на Regtest101.com. Заменит ли это все вхождения? RegTester останавливается при первом появлении.
Так случилось, что я ждал длинного сценария CLI, работающего с моим отладчиком, поэтому тем временем проводил исследования.
@GDP Как видите, во всех других ответах используются гораздо более сложные регулярные выражения. Вот что я имел в виду, говоря «простой подход». Я также думал о регулярном выражении на основе \G, но когда у вас есть вся мощь языка PHP, этот подход является лучшим, IMHO, поскольку шаблон очень удобочитаем и легко улучшается, если вам нужно избегать определенных контекстов.
Вы можете использовать этот подход чистого регулярного выражения с поисковыми запросами и \G:
$re = '~\b(?:(?=(?:\pL\h+){3}\pL\b)|(?<!^)\G)(\pL)\h+(?=\pL\b)~';
$repl = preg_replace($re, '$1', $str);
Детали RegEx:
\b: граница слова соответствия(?:: Запустить группу без захвата
(?=(?:\pL\h+){3}\pL\b): Загляните вперед, чтобы убедиться, что у нас есть 3+ отдельных буквы, разделенных 1+ пробелами|: ИЛИ(?<!^)\G: \G утверждает позицию в конце предыдущего совпадения. (?<!^) гарантирует, что мы не совпадаем с началом строки для первого совпадения): конец группы без захвата(\pL): сопоставьте одну букву и запишите ее\h+: за ним следует 1+ горизонтальных пробелов(?=\pL\b): Утверждаю, что впереди всего одна буква$1, который представляет собой букву слева от пробела, которую мы фиксируем.Кажется, это тоже работает, но я должен принять другой ответ, поскольку он ответил первым, помог мне начать в правильном направлении, но СПАСИБО!
Вы можете сделать это за один раз:
(?i:(?<!\S)([a-z]) +((?1))|\G(?!\A) +((?1))\b)
Объяснение:
(?i: # Start of non-capturing group with case-insensitive modifier on
(?<!\S) # Negative lookbehind to ensure there is no leading non-whitespace character
([a-z]) + # Capture one letter and at least one space
((?1)) # Capture one letter in 2nd capturing group
| # Or
\G(?!\A) + # Start match from where previous match ends
# with matching spaces
((?1))\b # Match a letter at word boundary
) # End of non-capturing group
Код PHP:
$str = preg_replace('~(?i:(?<!\S)([a-z]) +((?1))|\G(?!\A) +((?1))\b)~', '$1$2$3', $str);
Кажется, это тоже работает, но я должен принять другой ответ, поскольку он ответил первым, помог мне начать в правильном направлении, но СПАСИБО!
Вы должны использовать простой подход с
preg_replace_callback. Сопоставьте пробелы'~\b[A-Za-z](?: [A-Za-z]){2,}\b~'иstr_replaceв анонимной функции.