Регулярное выражение для соответствия экранированных символов (кавычки) - PullRequest
9 голосов
/ 29 июня 2011

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

"This is valid"
"This is \" also \" valid"

Очевидно, что-то вроде

"([^"]*)"

не работает, потому что соответствует первой экранированной кавычке.

Какая версия верна?

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

Кстати, я знаю о регулярном выражении "catch-all"

"(.*?)"

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

Ответы [ 5 ]

14 голосов
/ 29 июня 2011

Вот тот, который я использовал в прошлом:

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

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

Например, шаблон будет захватывать "This is valid" и "This is \" also \" valid" из этой строки:

"This is valid" this won't be captured "This is \" also \" valid"

Этот шаблон не будет соответствовать строке "I don't \"have\" a closing quote и позволит использовать дополнительные escape-коды в строке (например, он будет соответствовать "hello world!\n").

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

"(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")"
4 голосов
/ 04 января 2017

Проблема со всеми остальными ответами состоит в том, что они совпадают только для первоначального очевидного тестирования, но не дотягивают до дальнейшего изучения. Например, все ответы ожидают, что первая цитата не будет экранирована. Но самое главное, экранирование - более сложный процесс, чем просто обратная косая черта, поскольку саму обратную косую черту можно избежать. Представьте, что вы пытаетесь сопоставить строку, которая заканчивается обратной косой чертой. Как это возможно?

Это будет шаблон, который вы ищете. Он не предполагает, что первая кавычка является рабочей, и он позволит избежать обратной косой черты.

(?<!\\)(?:\\{2})*"(?:(?<!\\)(?:\\{2})*\\"|[^"])+(?<!\\)(?:\\{2})*"
3 голосов
/ 29 июня 2011

Попробуйте это ... Он предпочитает \", если он совпадает, он выберет его, в противном случае он выберет ".

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

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

Редактировать: Исправлена ​​логика группировки.

1 голос
/ 23 февраля 2018

Этот

("((?:[^"\\])*(?:\\\")*(?:\\\\)*)*")

будет захватывать все строки (в двойных кавычках), включая \ "и \\ escape-последовательности. (Обратите внимание, что в этом ответе предполагается, что only escape-последовательности вваша строка \ "или \\ sequence - никакие другие символы обратной косой черты или escape-последовательности не будут захвачены.)

("(?:         # begin with a quote and capture...
  (?:[^"\\])* # any non-\, non-" characters
  (?:\\\")*   # any combined \" sequences
  (?:\\\\)*   # and any combined \\ sequences
  )*          # any number of times
")            # then, close the string with a quote

Попробуйте это здесь!

Также обратите внимание, что принятый ответ Максимюка содержит «крайний случай» («Представьте, что вы пытаетесь сопоставить строку, которая заканчивается обратной косой чертой»), которая на самом деле является просто искаженной строкой.Что-то вроде

"this\"

... это не «строка, заканчивающаяся обратной косой чертой», а незамкнутая строка, оканчивающаяся на экранированную кавычку.Строка, которая действительно заканчивается обратной косой чертой, будет выглядеть как

"this\\"

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


Если вы хотите немного расширить, вот это...

(\\(?:b|t|n|f|r|\"|\\)|\\(?:(?:[0-2][0-9]{1,2}|3[0-6][0-9]|37[0-7]|[0-9]{1,2}))|\\(?:u(?:[0-9a-fA-F]{4})))

... захватывает все распространенные escape-последовательности (включая экранированные кавычки):

(\\                       # get the preceding slash (for each section)
  (?:b|t|n|f|r|\"|\\)     # capture common sequences like \n and \t

  |\\                     # OR (get the preceding slash and)...
  # capture variable-width octal escape sequences like \02, \13, or \377
  (?:(?:[0-2][0-9]{1,2}|3[0-6][0-9]|37[0-7]|[0-9]{1,2}))

  |\\                     # OR (get the preceding slash and)...
  (?:u(?:[0-9a-fA-F]{4})) # capture fixed-width Unicode sequences like \u0242 or \uFFAD
)

См. этот Гист для получения дополнительной информации о втором пункте.

1 голос
/ 27 марта 2017

Ниже приведен код, содержащий оценку выражений для Строка , Число и Десятичное число .

public static void commaSeparatedStrings() {        
    String value = "'It\\'s my world', 'Hello World', 'What\\'s up', 'It\\'s just what I expected.'";

    if (value.matches("'([^\'\\\\]*(?:\\\\.[^\'\\\\])*)[\\w\\s,\\.]+'(((,)|(,\\s))'([^\'\\\\]*(?:\\\\.[^\'\\\\])*)[\\w\\s,\\.]+')*")) {
        System.out.println("Valid...");
    } else {
        System.out.println("Invalid...");
    }
}

/**
 * 
 */
public static void commaSeparatedDecimals() {
    String value = "-111.00, 22111.00, -1.00";
    // "\\d+([,]|[,\\s]\\d+)*"
    if (value.matches(
            "^([-]?)\\d+\\.\\d{1,10}?(((,)|(,\\s))([-]?)\\d+\\.\\d{1,10}?)*")) {
        System.out.println("Valid...");
    } else {
        System.out.println("Invalid...");
    }
}

/**
 * 
 */
public static void commaSeparatedNumbers() {
    String value = "-11, 22, -31";      
    if (value.matches("^([-]?)\\d+(((,)|(,\\s))([-]?)\\d+)*")) {
        System.out.println("Valid...");
    } else {
        System.out.println("Invalid...");
    }
}
...