Regex;обратная ссылка на символ, который НЕ совпал в наборе символов - PullRequest
7 голосов
/ 15 марта 2012

Я хочу создать регулярное выражение, которое соответствует либо ' или ", а затем совпадает с другими символами, заканчиваясь при совпадении ' или " соответственно, в зависимости от того, что встречалось в самом начале,Таким образом, эта проблема кажется достаточно простой для решения с использованием обратной ссылки в конце;ниже приведен некоторый код регулярного выражения (это на Java, так что учтите дополнительные экранирующие символы, такие как \ перед "):

private static String seekerTwo = "(['\"])([a-zA-Z])([a-zA-Z0-9():;/`\\=\\.\\,\\- ]+)(\\1)";

Этот код будет успешно работать с такими вещами, как:

"hello my name is bob"
'i live in bethnal green'

Проблема возникает, когда у меня есть такая строка:

"hello this seat 'may be taken' already"

Использование приведенного выше регулярного выражения завершится неудачно в начальной части при обнаружении ', затем продолжится и успешноmatch 'may be taken' ... но этого явно недостаточно, мне нужно сопоставить всю строку.

Я думаю, что мне нужен способ игнорировать тип кавычки, который былНЕ подходит в самой первой группе, включая его как символ в набор символов 3-й группы.Однако я не знаю, как это сделать.Есть какая-то хитрая функция обратной ссылки или что-то в этом роде?Что-то, что я могу использовать, чтобы сослаться на персонажа в 1-й группе, который НЕ соответствовал ??Или иначе какое-то решение моей проблемы?

Ответы [ 2 ]

12 голосов
/ 15 марта 2012

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

(["'])(?:\\.|(?!\1).)*\1

Объяснение:

(["'])    # Match and remember a quote.
(?:       # Either match...
 \\.      # an escaped character
|         # or
 (?!\1)   # (unless that character is identical to the quote character in \1)
 .        # any character
)*        # any number of times.
\1        # Match the corresponding quote.

Это правильно соответствует "hello this seat 'may be taken' already" или"hello this seat \"may be taken\" already".

В Java со всеми обратными слешами:

Pattern regex = Pattern.compile(
    "([\"'])   # Match and remember a quote.\n" +
    "(?:       # Either match...\n" +
    " \\\\.    # an escaped character\n" +
    "|         # or\n" +
    " (?!\\1)  # (unless that character is identical to the matched quote char)\n" +
    " .        # any character\n" +
    ")*        # any number of times.\n" +
    "\\1       # Match the corresponding quote", 
    Pattern.COMMENTS);
2 голосов
/ 15 марта 2012

Решение Тима работает довольно хорошо, если вы можете использовать lookaround (который поддерживает Java).Но если вам нужно использовать язык или инструмент, который не поддерживает обходные пути, вы можете просто сопоставить оба случая (строки в двойных кавычках и строки в одинарных кавычках):

"(\\"|[^"])*"|'(\\'|[^'])*'

соответствует каждому случаю отдельно, но возвращаетв любом случае как полное совпадение


ОДНАКО

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

Он повернулся, чтобы сесть на велосипед.«Увидимся позже, когда я закончу со всем этим», - сказал он, оглядываясь на мгновение, прежде чем начать свое путешествие.Когда он вышел на улицу, одна из городских тележек столкнулась с велосипедом Майка."О боже!"воскликнул наблюдатель.

... но есть три совпадения, а не два:

"I'll see you later, when I'm done with all this"
's trolleys collided with Mike'
"Oh my!"

, и этот отрывок содержит только ONE матч:

Однако бой еще не закончился."Привет!"крикнул Боб."Чего ты хочешь?"Я ответил."Я ненавижу твои кишки!""Зачем мне все равно?""Потому что я тебя люблю!""Ты сделаешь?"Боб остановился на мгновение, прежде чем прошептать: «Нет, я не могу тебя любить!»

Ты можешь найти это?: D

't over yet, though. "Hey!" yelled Bob. "What do you want?" I retorted. "I hate your guts!" "Why would I care?" "Because I love you!" "You do?" Bob paused for a moment before whispering "No, I couldn'

Я бы порекомендовал (если вы готовы использовать lookaround), чтобы вы рассмотрели некоторые дополнительные проверки (например, положительный просмотр за пробелами или аналогичные перед первой цитатой), чтобы убедиться, что выне подходите к вещам вроде 's trolleys collided with Mike' - хотя я бы не стал вкладывать много денег в какое-либо решение без большого количества тестирования.Добавление (?<=\s|^) в начало любого выражения позволит избежать вышеупомянутых случаев ... т.е.:

(?<=\s|^)(["'])(?:\\.|(?!\1).)*\1                    #based on Tim's

или

(?<=\s|^)("(\\"|[^"])*"|'(\\'|[^'])*')               #based on my alternative

Я не уверен, насколько эффективен поиск по сравнению сне имеет смысла, поэтому два приведенных выше могут быть эквивалентными, или один может быть более эффективным, чем другой (?)

...