Группировка в символьных классах regexp

12
RS
На сайте с 26.02.2010
Offline
13
1376

Добрый день :) Вопрос по регулярным выражениям.

Подскажите пожалуйста варианты решения проблемы. Связана она с исключающими символьными классами [ ... ].

Вот например, паттерн

/[^abcd]/

соответствует любому символу в строке, за исключением этих четырех букв. Например: alphabet

Мне необходимо сгруппировать символы в этом исключающем списке, написать что-то типа

/[^(ab)(cd)]/

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

Чтобы было: alphabet

Т.е. надо найти все слова, в которых нет конкретной последовательности символов, например (ab) или (cd).

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

Подскажите, как это можно реализовать, каким регексом?

Хорс
На сайте с 14.12.2010
Offline
21
#1

Очень мутно...

Вас просто интересует разъяснение по POSIX regex, или есть конкретная задача?

Типа надо на PHP/Perl/JavaScript (и т.д.) при обработке текста:

  • игнорировать строки содержащие вхождение
  • вычленять из строк вхождение
  • что то другое
RS
На сайте с 26.02.2010
Offline
13
#2

а. :)

Мне нужно игнорировать строки, которые содержат определенную последовательность символов. Работаю с PHP.

Есть конкретная задача, вопрос просто упрощен до минимума, чтобы найти "базу", от которой я дальше буду отталкиваться. Ну вот, например, тоже простой пример, но уже практический.

Есть строка: "собака обама акваланг абстракция апельсин".

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

В результате надо иметь совпадения: "собака обама акваланг апельсин абстракция".

Ближайший приходящий на ум вариант, это перечислить эти неугодные буквы в [^...], но в таком случае будут игнорироваться слова с любой из четырех перечисленных букв, а мне необходимы именно конкретные последовательности "ба" и "ап".

Хорс
На сайте с 14.12.2010
Offline
21
#3

А такая конструкция не пойдёт?

Либо придётся городить в стиле /[^о]{1}[^б]{1}/iu


header('Content-Type: text/plain; charset=utf-8');
$a = explode(' ','собака обама акваланг абстракция апельсин боты');
$words = array();

foreach ($a as $v)
if (! preg_match("/(об|ап)/iu", $v))
array_push($words,$v); # А то квадратные скобки глючат на этом форуме =)

print_r($words);
RS
На сайте с 26.02.2010
Offline
13
#4

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

По факту у меня текст из вложенных блоков, типа:

{block}в первом {block}во втором{/block} в первом{/block} вне блоков {block}опять в блоке{/block}

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

Так вот для правильного выбора того что мне нужно, в регулярке надо в одном месте перечислить в исключающем множестве открывающие и закрывающие теги блоков. Будь они одним символом, например (скобками):

(в первом (во втором) в первом) вне блоков (опять в блоке)

Все решается легко, потому что можно указать [^()]. И дело в шляпе. А у меня последовательность символов {block}, которую я не знаю как записать с тем же эффектом.

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

Joker-jar
На сайте с 26.08.2010
Offline
171
#5

Думаю, подобную задачу (с вложенностью) надо решать чем-то типа конечных автоматов. Блоки со вложенными подблоками вообще не нужно обрабатывать или как?

Хорс
На сайте с 14.12.2010
Offline
21
#6

Никак не могу понять задачу. Буду задавать наводящие вопросы.

Есть текст:

Электролиз ясен {block}биуретовая реакция восстановлена {block}выпадение
испускает белок, {block}образуя{/block} кристаллы {block}кубической
формы{/block}{/block}. Энергетический подуровень, даже при наличии
сильных кислот, синтезирует коллоидный энергетический подуровень как при
возбуждении, так и при релаксации.{/block} Возгонка ингибирует
энергетический синтез {block}минуя жидкое состояние{/block}.

С примерно такой структурой:

  • Текст вне блока
    • Первый уровень вложенности
      • Второй уровень вложенности
        • Третий уровень вложенности

Задача:

  • Найти и обработать слова во всём тексте, не повредив служебные тэги {block} и {/block}
  • Найти и обработать слова не входящие в блоки (отмечен зелёным)
  • Найти и обработать слова входящие в блок определённого уровня, исключив подуровни (например только текст помеченный синим)
  • Найти и обработать слова входящие в блок определённого уровня, включая подуровни (например голубой, синий, красный)
  • Найти и обработать все слова, исключая блок определённого уровня (например всё, кроме синего)
  • Другое
siv1987
На сайте с 02.04.2009
Offline
427
#7
Хорс:
Никак не могу понять задачу. Буду задавать наводящие вопросы.

Хорс, нужно исключить слова которые содержат определенные буквы в строгой последовательности, чего непонятного.

2ТС

Классам никак, в нем не группируются символы.

RS
На сайте с 26.02.2010
Offline
13
#8

Я польщён оживленностью в моей теме :)

Хорс, спасибо, что вы тратите свое время задавая такие подробные и разукрашенные вопросы :)

Так, значит, сейчас еще раз кое-что объясню, может быть и вопросы иссякнут.

Есть такая классная штука как рекурсивные регулярки: http://ua2.php.net/manual/en/regexp.reference.recursive.php

Вот ниже пример их работы:


$string = 'outside (one (two) one2) outside2 (three)';
$pattern = '@
\(
(
[^()]+
|(?R)
)*
\)
@sx';
preg_match_all($pattern, $string, $matches);
var_dump($matches);

Мой случай практически идентичен зи исключением того, что в этом примере тегами блоков являются скобки "(" и ")", а в моем случае - последовательности символов "{block}" и "{/block}". К слову говоря у них еще параметры есть, но не будем усложнять. По факту мне еще нужно будет дописать паттерн для разделителей типа {block $lala = $blabla}

Так вот, в примере в результате отработки паттерна мы получаем в результатах:


array
0 => (one (two) one2)
1 => (three)
Joker-jar:
Блоки со вложенными подблоками вообще не нужно обрабатывать или как?

Нужно, я это уже смогу сделать по той же схеме рекурсивно. Они у нас, как видите выше, в первом совпадении в массиве.

Ну и вот, проблема. Когда разделители скобки: в паттерне юзается [^()]+

Когда разделители {block} - хрен его знает как этот паттерн поправить, чтобы он отработал с тем же эфффектом. Вот и весь вопрос :)

Хорс
На сайте с 14.12.2010
Offline
21
#9
siv1987:
Хорс, нужно исключить слова которые содержат определенные буквы в строгой последовательности, чего непонятного.

Мне не понятно, причём тут тогда упоминание блоков. Читайте тему целиком.

RS
На сайте с 26.02.2010
Offline
13
#10

Лучше читать сразу мое предыдущее сообщение. Все это выше - для упрощения.

Вопрос не поменялся, но в предыдущем сообщении он в контексте конкретной проблемы.

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий