Регулярные выражения, понимающие ретроспективу в сочетании с оператором или

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

Примеры:

  1. "1,23"
  2. "12,23"
  3. "123,23"

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

(?<=\"[0-9]|[0-9]{2})(,)(?=[0-9]{2}\")

Часть, которую я не совсем понимаю, - это ретроспективный просмотр в сочетании с или "|". Но давайте разберемся:

(
?<=             //Start of the lookbehind
\"              //Starting with an escaped quotation mark "
[0-9]           //Followed by a digit between 0 and 9

Теперь у меня была проблема, что после кавычки не всегда была одна цифра, как вы можете видеть в примерах 2 и 3. Оператор диапазона, например. {1,3} не работала в ретроспективе. Как я узнал в другом вопросе о переполнении стека.

Поэтому я решил использовать или "|" как предложено здесь:

|[0-9]{2}       //Or followed by two digits between 0 and 9
)

Интересно то, что он также соответствует запятой в третьем примере «123,23». Я действительно не понимаю почему. Также я не знаю, почему мне не нужно добавлять начальную кавычку после или "|" снова, потому что я думал, что полный просмотр назад до тех пор, пока оператор или не будет необходимо изменить или повторить, например:

(?<=\"[0-9]|\"[0-9]{2})(,)(?=[0-9]{2}\")            //This however does not work at all

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

(?<=\"[0-9]|\"[0-9]{2}|\"[0-9]{3})(,)(?=[0-9]{2}\")

или хотя бы (если кто-то сможет объяснить пропажу \ "):

(?<=\"[0-9]|[0-9]{2}|[0-9]{3})(,)(?=[0-9]{2}\")

Я надеюсь, что кто-то сможет помочь мне разобраться в ситуации.

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


person Kevin    schedule 07.08.2015    source источник
comment
(?<=\"[0-9]|[0-9]{2}) соответствует всем запятым в этих примерах   -  person wiktus239    schedule 07.08.2015


Ответы (1)


Ты прав,

(?<=\"[0-9]|\"[0-9]{2}|\"[0-9]{3})(,)(?=[0-9]{2}\")

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


О том, почему вам "не нужен \" для двух и трех цифр" - он вам действительно нужен.

(?<=\"[0-9]|[0-9]{2}|[0-9]{3})(,)(?=[0-9]{2}\")

Также будет соответствовать 12,23" и 123,23".


EDIT: похоже, проблема в том, что Sublime не допускает переменную длину просмотра назад, даже если они указаны с |. Значение (?<=\"[0-9]|\"[0-9]{2}|\"[0-9]{3}) не удастся, потому что альтернативы имеют разные размеры - 2, 3, 4.

Это потому, что Sublime, похоже, использует Библиотека Boost регулярных выражений. Там сказано:

Смотреть за

(?<=pattern) использует ноль символов, только если шаблон может быть сопоставлен с символами, предшествующими текущей позиции (шаблон должен иметь фиксированную длину).

(?<!pattern) использует ноль символов, только если шаблон не может быть сопоставлен с символами, предшествующими текущей позиции (шаблон должен иметь фиксированную длину).

Альтернативой является разделение ретроспективного просмотра:

(?:(?<=\"[0-9])|(?<=\"[0-9]{2})|(?<=\"[0-9]{3}))(,)(?=[0-9]{2}\")


Что делать, если вы не хотите перечислять все возможные длины?

Есть классный трюк, который присутствует в некоторых движках регулярных выражений (включая Perl, Ruby и Sublime) - \K. Примерно \K означает «отбросить все, что было найдено до сих пор». Следовательно, вы можете сопоставить любой , в числе с плавающей запятой, заключенный в кавычки, с:

"\d+\K,(?=\d+")

Посмотрите на это в действии

person ndnenkov    schedule 07.08.2015
comment
Что ж, я имею в виду, что возвышенный текст не принимает (?<=\"[0-9]|\"[0-9]{2})(,)(?=[0-9]{2}\") и сообщает следующую ошибку: В регулярном выражении обнаружено недопустимое утверждение просмотра назад, то же самое с (?<=\"[0-9]|\"[0-9]{2}|\"[0-9]{3})(,)(?=[0-9]{2}\"). Но да, "\d+\K,(?=\d+") отлично работает в этом конкретном случае. Спасибо за это. Может быть, это просто проблема возвышенного текста, а не проблема самого регулярного выражения? - person Kevin; 07.08.2015
comment
Если это просто проблема возвышенного текста, я могу с этим жить. Большое спасибо за этот ответ. Это очень помогло мне понять. - person Kevin; 07.08.2015
comment
Я провел дополнительное расследование и обновил свой ответ, чтобы объяснить, почему в Sublime есть это ограничение и как вы можете его обойти. - person ndnenkov; 07.08.2015
comment
Еще раз спасибо за ваши усилия. Я очень ценю это. - person Kevin; 07.08.2015