регулярное выражение, чтобы удалить все пробелы, кроме в скобках - PullRequest
3 голосов
/ 31 июля 2009

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

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

Примеры:

  • ааа [bb b]
  • aaa [bbb] ccc [d dd]
  • [ааа] bbb [c cc]

Вы можете видеть, что в некоторых из подстрок в скобках есть пробелы, это нормально. Моя главная проблема сейчас, когда я сталкиваюсь с пробелами за скобками, например:

  • aaa [bb b]

Теперь я хочу сохранить пробелы внутри скобок, но убрать их повсюду.

Это немного сложнее для строк вроде:

  • aaa [bb b] ccc [d dd] ee [f ff]

Здесь я хотел бы, чтобы возвращение было:

  • aaa [bb b] ccc [d dd] eee [f ff]

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

ПРИМЕЧАНИЕ: для тех, кто посещал это, я не искал решения, включающего вложенные скобки. Если бы это было так, я бы, вероятно, сделал это прагматично, как некоторые из комментариев, упомянутых ниже.

Ответы [ 6 ]

11 голосов
/ 31 июля 2009

Это регулярное выражение должно сделать трюк:

[ ](?=[^\]]*?(?:\[|$))

Просто замените пробел на "".

По сути, все, что он делает - это проверяет, чтобы пространство, которое вы собираетесь удалить, имело перед собой "[", но не если перед ним стоит "]".

Это должно работать, если у вас нет вложенных квадратных скобок, например ::10000

a a [b [c c] b]

Потому что в этом случае пробел после первого «b» будет удален и станет:

aa [b [c c] b]

8 голосов
/ 31 июля 2009

Это не похоже на то, что вы действительно хотите регулярное выражение для. Это очень легко разобрать напрямую, прочитав. Псевдо-код:

inside_brackets = false;
for ( i = 0; i < length(str); i++) {
    if (str[i] == '[' )
        inside_brackets = true;
    else if str[i] == ']'
        inside_brackets = false;
    if ( ! inside_brackets && is_space(str[i]) )
        delete(str[i]);
}

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

Чтобы это работало для вложенных скобок, просто измените inside_brackets на счетчик, начиная с нуля, увеличивая на открытые скобки и уменьшая на закрывающие скобки.

2 голосов
/ 31 июля 2009

Это работает для меня:

(\[.+?\])|\s

Затем вы просто передаете значение замены $ 1, когда вызываете функцию замены. Идея состоит в том, чтобы сначала найти шаблоны внутри скобок и убедиться, что они не тронуты. И тогда все пробелы за скобками заменяются ничем.

Обратите внимание, что я проверял это с Regex Hero (тестером регулярных выражений .NET), а не с PHP. Так что я не уверен на 100%, что это сработает для вас.

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

1 голос
/ 20 мая 2014

Воскрешение этого вопроса, потому что у него было простое решение, которое не было упомянуто.

\[[^]]*\](*SKIP)(*F)|\s+

Левая часть чередования соответствует полному набору скобок, а затем намеренно терпит неудачу. Правая сторона сопоставляет и захватывает пробелы для группы 1, и мы знаем, что они являются правильными пробелами, потому что, если бы они были в скобках, они были бы ошибочными из-за выражения слева.

Смотрите матчи в этой демоверсии

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

$replace = preg_replace("~\[[^]]*\](*SKIP)(*F)|\s+~","",$string);

Ссылка

  1. Как сопоставить шаблон с исключением ситуаций s1, s2, s3
  2. Как сопоставить шаблон, если ...
1 голос
/ 31 июля 2009

Как это сделать, зависит от того, что должно быть сделано с:

a b [ c [ d [ e ] f ] g

Это неоднозначно; возможные ответы как минимум:

  • ab[ c [ d [ e ] f ]g
  • ab[ c [ d [ e ]f]g
  • ошибка; скобки не совпадают!

Для первых двух случаев вы можете использовать регулярные выражения. В третьем случае вам будет гораздо лучше с (маленьким) парсером.

В любом случае, один или два, разбейте строку на первый [. Уберите пробелы из всего, что было до [ (это явно за скобками). Затем найдите .*\] (случай 1) или .*?\] (случай 2) и перенесите это на свой выход. Повторяйте, пока не закончите ввод.

0 голосов
/ 31 июля 2009

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

/((^|\])[^ \[]*) +/

замена "all" на $1 удалит первый блок пробелов из каждой последовательности без скобок. Вам придется повторить матч, чтобы удалить все пробелы.

Пример:

abcd efg [hij klm]nop qrst u
abcdefg [hij klm]nopqrst u
abcdefg[hij klm]nopqrstu
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...