Intereting Posts
Получение имени дочернего класса в родительском классе (статический контекст) Как получить доступ к моему Wamp Server на другом локальном компьютере facebook приложение получает перенаправленный вид холста Outlook API OAuth2 автономный доступ / постоянный доступ с использованием php Это правильный способ уничтожить все данные сеанса в php? PHPUnit утверждает, что не вызывается метод Как создать удобный для пользователя URL-адрес с использованием псевдонима и идентификатора из базы данных? Почему так плохо запускать PHP-скрипт? make html table <thead> исправлено при прокрутке в динамическом <tbody> в php Альтернатива mysql_real_escape_string без подключения к DB Может ли APC повысить скорость выполнения CLI-скриптов при использовании с pcntl_fork ()? Структуру дерева PHP для категорий и подкатегорий без циклического запроса Публикация изображения + статус с помощью API Twitter с помощью php маршрутизация по умолчанию в codeigniter Упростить фракцию

Получить все вложенные фигурные скобки

Можно получить все содержимое в вложенных фигурных скобках из строки? Например:

Быстрая коричневая лиса прыгает через ленивую собаку

Мне нужно:

  • быстро
  • над
  • прыгает {над} ленивым

Лучше в этой последовательности, от большинства вложенных.

Решение

Регулярное выражение ниже позволит вам захватить содержимое всех вложенных фигурных скобок. Обратите внимание, что это предполагает, что вложенные фигурные скобки сбалансированы; в противном случае трудно определить, какой должен быть ответ.

(?=\{((?:[^{}]++|\{(?1)\})++)\}) 

Результатом будет захват группы 1.

DEMO

Обратите внимание, что порядок не задан в вопросе. Распечатанный заказ определяется порядком появления открывающей фигурной скобки { , что означает, что сначала будет напечатано содержимое самой внешней пары.

объяснение

Игнорирование положительного внешнего вида с нулевой шириной (?=pattern) на данный момент, и давайте сосредоточимся на шаблоне внутри, который:

 \{((?:[^{}]++|\{(?1)\})++)\} 

Часть между двумя буквальными фигурными фигурными скобками – ((?:[^{}]++|\{(?1)\})++) будет соответствовать 1 или более экземплярам:

  • непустую последовательность не фигурных скобок символов [^{}]++ или
  • рекурсивно соответствуют блоку, заключенному в {} , который может содержать множество других не-фигурных скобок или других блоков.

Вышеупомянутый шаблон может соответствовать тексту, который не содержит {} , что нам не нужно. Поэтому мы убеждаемся, что совпадение представляет собой блок, заключенный {} парой фигурных скобок {} в 2 концах: \{((?:[^{}]++|\{(?1)\})++)\} .

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

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

Обычный код может обрабатывать все эффективно за один проход, и рекомендуется, если вы собираетесь продлить свое требование в будущем.

Простое решение без регулярного выражения за один проход:

 $str = 'The {quick} brown fox {jumps {over the} lazy} dog'; $result = parseCurlyBrace($str); echo '<pre>' . print_r($result,true) . '</pre>'; function parseCurlyBrace($str) { $length = strlen($str); $stack = array(); $result = array(); for($i=0; $i < $length; $i++) { if($str[$i] == '{') { $stack[] = $i; } if($str[$i] == '}') { $open = array_pop($stack); $result[] = substr($str,$open+1, $i-$open-1); } } return $result; } 

Вы можете попробовать следующее:

 $subject = 'The {quick} brown fox {jumps {over the} lazy} dog'; function nestor($subject) { $result = false; preg_match_all('~[^{}]+|\{(?<nested>(?R)*)\}~', $subject, $matches); foreach($matches['nested'] as $match) { if ($match != "") { $result[] = $match; $nesty = nestor($match); if ($nesty) $result = array_merge($result,$nesty); // $result[]=$nesty; // to preserve the hierarchy } } return $result; } print_r(nestor($subject)); 

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

Вы можете изучить другой способ с помощью этого другого шаблона с помощью модификатора \ G:

 $subject = 'The {quick} brown fox {jumps {over the}{ fat} lazy} dog'; $pattern = '~[^{}]++|\G\{(?<nested>(?R)*+)\}~'; preg_match_all($pattern, $subject, $matches/*, PREG_SET_ORDER*/); print_r($matches); 

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

Вы можете сделать это взломанным, уродливым образом следующим образом:

1) Искать все совпадения регулярного выражения {([^}]*)}

2) Найдите все совпадения регулярного выражения {([^}]*{[^}]*}[^}]*)} (как вы можете видеть, это может быть динамически построено)

3) Найдите все совпадения регулярного выражения {([^}]*{[^}]*{[^}]*}[^}]*}[^}]*)} … (продолжайте динамически строить его больше, пока вы не получите совпадений)

Группа захвата, обозначенная символом () только внутри внешней пары {} s, позволит вам захватить только то, что находится в первой группе захвата, а не полностью совпадение регулярных выражений.