Regex для соответствия значениям, не окруженным другим символом?

Эта проблема была только что исправлена ​​ здесь .

Так, например:

obj
 .func1 "aaa"
 .func2 "bbb"

будет скомпилировано в

obj.func1("aaa").func2("bbb");

Возможно, вам придется использовать последнюю версию в основной ветке сейчас, в npm:

npm install -g http://github.com/jashkenas/coffee-script/tarball/master

7
задан TRiG 28 May 2013 в 13:16
поделиться

6 ответов

Лучшее решение будет зависеть от того, что вы знаете о вводе. Например, если вы ищете вещи, которые не заключены в двойные кавычки, означает ли это, что двойные кавычки всегда будут правильно сбалансированы? Можно ли их избежать с помощью обратной косой черты или заключив их в одинарные кавычки?

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

preg_match('/THIS(?=(?:(?:[^"]*+"){2})*+[^"]*+\z)/')

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

Как вы обнаружили, эта проблема не подходит для регулярных выражений; поэтому все предлагаемые решения зависят от функций, которые не t найдено в реальных регулярных выражениях, таких как группы захвата, поисковые пути, неохотные и притяжательные кванторы. Я бы даже не пытался это без притяжательных кванторов или атомных групп .

РЕДАКТИРОВАТЬ: Чтобы расширить это решение, чтобы учесть двойные кавычки, которые могут быть экранированные обратной косой чертой, вам просто нужно заменить части регулярного выражения, которые соответствуют «всем, что не является двойной кавычкой»:

[^"]

на «все, что не является кавычкой, обратной косой чертой или обратной косой чертой, за которой следует что-либо»:

(?:[^"\\]|\\.)

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

(?:[^"\\]++|\\.)

Собирая все вместе, регулярное выражение становится:

'/THIS\d+(?=(?:(?:(?:[^"\\]++|\\.)*+"){2})*+(?:[^"\\]++|\\.)*+$)/'

Применяется к вашему тестовая строка:

'Match THIS1 and "NOT THIS2" but THIS3 and "NOT "THIS4" or NOT THIS5" ' +
'but \"THIS6\" is good and \\\\"NOT THIS7\\\\".'

...

14
ответ дан 6 December 2019 в 10:02
поделиться

Ну, регулярные выражения - просто неподходящий инструмент для этого, поэтому вполне естественно, что это сложно.

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

Для HTML / XML просто используйте HTML, соответственно. Парсер XML; они существуют практически для любого языка или веб-фреймворка; их использование обычно требует всего нескольких строк кода. Для таблиц вы можете использовать синтаксический анализатор CSV или, в крайнем случае, создать собственный синтаксический анализатор, который извлекает части внутри / снаружи кавычек. После извлечения интересующих вас частей,

1
ответ дан 6 December 2019 в 10:02
поделиться

Это немного сложно . Есть способы, если вам не нужно отслеживать вложенность. Например, давайте избегать цитируемого материала:

^((?:[^"\\]|\\.|"(?:[^"\\]|\\.)*")*?)THIS

Или, поясняя:

^     Match from the beginning
(     Store everything from the beginning in group 1, if I want to do replace
    (?:  Non-grouping aggregation, just so I can repeat it
        [^"\\]  Anything but quote or escape character
        |       or...
        \\.     Any escaped character (ie, \", for example)
        |       or...
        "       A quote, followed by...
        (?:     ...another non-grouping aggregation, of...
            [^"\\]  Anything but quote or escape character
            |       or...
            \\.     Any escaped character
        )*      ...as many times as possible, followed by...
        "       A (closing) quote
    )*?  As many as necessary, but as few as possible
)     And this is the end of group 1
THIS  Followed by THIS

Теперь есть другие способы сделать это, но, возможно, не такой гибкий. Например, если вы хотите найти ЭТО при условии, что не было предшествующей последовательности «//» или «#» - другими словами, ЭТО вне комментария, вы можете сделать это следующим образом:

(?<!(?:#|//).*)THIS

Здесь (? - отрицательный просмотр назад. Он не будет соответствовать этим символам, но проверит, что они не появляются перед ЭТОМ.

Что касается любых произвольно вложенных структур - n ( закрыто n ]) , например - они не могут быть представлены регулярными выражениями. Perl может это сделать, но это не регулярное выражение.

(?<!(?:#|//).*)THIS

Здесь (? - отрицательный взгляд назад. Он не будет соответствовать этим символам, но проверит, что они не появляются перед ЭТОМ.

Что касается любых произвольно вложенных структур - n ( закрыто n ]) , например - они не могут быть представлены регулярными выражениями. Perl может это сделать, но это не регулярное выражение.

(?<!(?:#|//).*)THIS

Здесь (? - отрицательный взгляд назад. Он не будет соответствовать этим символам, но проверит, что они не появляются перед ЭТОМ.

Что касается любых произвольно вложенных структур - n ( закрыто n ]) , например - они не могут быть представлены регулярными выражениями. Perl может это сделать, но это не регулярное выражение.

3
ответ дан 6 December 2019 в 10:02
поделиться

См. Text :: Balanced для Perl и FAQ по Perl .

1
ответ дан 6 December 2019 в 10:02
поделиться

После размышлений о вложении элементов («а», «это» и «это» ») и элементов с обратной косой чертой« \ "ЭТО \" »кажется, что это действительно правда, что это не работа для регулярного выражения.Однако единственное, что я могу придумать для решения этой проблемы, - это регулярное выражение, такое как парсер char-by-char, который будет отмечать $ quote_level = ###; при поиске и вводе действительной цитаты или дополнительной цитаты. Таким образом, находясь в этой части строки, вы будете знать, находитесь ли вы внутри какого-либо заданного символа, даже если он экранирован косой чертой или чем-то еще.

Я думаю, что с помощью парсера char-by-char вы могли бы отметить строку положение начальных / конечных кавычек, чтобы вы могли разбить строку на сегменты кавычек и обрабатывать только те, которые находятся вне кавычек.

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

Match THIS and "NOT THIS" but THIS and "NOT "THIS" or NOT THIS" but \"THIS\" is good.

//Parser "greedy" looking for nested levels
Match THIS and "
            NOT THIS"
                but THIS and "
                        NOT "
                            THIS"
                                or NOT THIS"
                                        but \"THIS\" is good

//Parser "ungreedy" trying to close nested levels
Match THIS and "        " but THIS and "    " THIS "            " but \"THIS\" is good.
                NOT THIS                NOT          or NOT THIS


//Parser closing levels correctly.
Match THIS and "        " but THIS and "                    " but \"THIS\" is good.
                NOT THIS                NOT "   " or NOT THIS
                                            THIS
0
ответ дан 6 December 2019 в 10:02
поделиться

Как указал Алан М, вы можете использовать регулярное выражение для поиска нечетного числа, тем самым информируя вас о вашей позиции внутри или вне любой данной строки. Взяв пример с цитатами, мы кажемся действительно близкими к решению этой проблемы. Осталось только обработать экранированные кавычки. (Я уверен, что вложенные кавычки практически невозможны.)

$string = 'Match THIS1 and "NOT THIS2" but THIS3 and "NOT "THIS4" or NOT THIS5" but \"THIS6\" is good and \\\\"NOT THIS7\\\\".';


preg_match_all('/[^"]+(?=(?:(?:(?:[^"\\\]++|\\\.)*+"){2})*+(?:[^"\\\]++|\\\.)*+$)/', $string, $matches);

Array (
        [0] => Match THIS1 and 
        [1] =>  but THIS3 and 
        [2] => THIS4
        [3] =>  but 
        [4] => THIS6
        [5] =>  is good and \\
        [6] => NOT THIS7\
        [7] => .
    )
0
ответ дан 6 December 2019 в 10:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: