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

Мне нужна для Java проверка последней строки. У меня есть строка, которая будет далее обрабатываться компилятором TeX. Там самый первый % в строке воспринимается как комментарий, а вся остальная часть строки «не видна» компилятору.

Но самый первый % немного сложен, потому что его можно экранировать с помощью \, поэтому \% следует игнорировать.

Итак, в основном я хочу проверить, заканчивается ли самая последняя строка комментарием или нет?

например

(a) last line % now with comment
(b) last line with escaped \%  and not treated
(c) last line withouth any special chars
(d) last line terminates with %
(e) last line terminates with escaped \%
(f) beginning % but even escaped \% is ignored

Для проверки мне нужно, чтобы a, d и f были положительными, а остальные следует игнорировать.

В соответствии с моим подходом до сих пор:

[^\n]*$

проверяет самую последнюю строку. Хорошо, но теперь я даже не знаю, как сопоставить в самой последней строке просто %. Я ожидал, что (%)? будет соответствовать, только если % доступен, но с четным (c) положительным, поскольку он соответствует последней строке.

Может ли кто-нибудь помочь, как отфильтровать только те %, которые я ищу?

Это все еще довольно расплывчато. Попробуйте (?<!\\)(?:\\{2})*\\%[^\\\r\n]*(?:\\(?!%)[^\\\r\n]*)*\z, см. regex101.com/r/Yqpvb1/1

Wiktor Stribiżew 10.12.2020 20:19

Кроме того, мое предположение, что [^\\] нужен двойной экран, не соответствует ни одной строке. Хм... я что-то пропустил.

LeO 10.12.2020 20:28

regex101.com/r/Yqpvb1/1 показывает правильное совпадение?

Wiktor Stribiżew 10.12.2020 22:06

Или вам нужен regex101.com/r/Yqpvb1/2?

Wiktor Stribiżew 10.12.2020 23:23

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

LeO 11.12.2020 20:08

Но какой из них работает для вас?

Wiktor Stribiżew 11.12.2020 20:12

Ах, простите, второй работает. Потому что первый ловит в конце сбежавший %, который не должен быть пойман. Но второй работает как положено.

LeO 11.12.2020 20:37
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
7
162
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Демо: https://regex101.com/r/oRqrhv/1

Выкройка: (?<!\\)%


Обновление 1: чтобы убедиться, что мы совпадаем только с последней строкой, можно использовать atomic group.

Выкройка: (?>[\s\S]*\n).*(?<!\\)%

Подробности: [\s\S]*\n будет соответствовать всем символам до последнего \n. Атомная группа (?>..) предотвратит возврат двигателя назад.

Успешное совпадение: https://regex101.com/r/oRqrhv/2
Неудачный матч: https://regex101.com/r/oRqrhv/4


Примечание. Если в конце введенного текста есть пустая новая строка, например https://regex101.com/r/oRqrhv/3, совпадения не будет. Если это необходимо сопоставить, нам нужно использовать отрицательный просмотр вперед.
Выкройка: (?>[\s\S]*\n(?<!$)).*(?<!\\)%. (?<!$) гарантирует, что за \n сразу не следует конец строки.

Это очень хорошая идея. Я бы сказал, что он соответствует моему запросу примерно на 90%. Есть ли способ применить отрицательный просмотр назад только для самой последней строки? Что-то вроде [^\n](?<!\\)%$ не работает. Я думал, что смогу инкапсулировать его для самой последней строки, но это не удается. Во всяком случае мне это нравится.

LeO 10.12.2020 20:34
Ответ принят как подходящий

Вы можете использовать

(?<!\\)(?:\\{2})*%[^\\%\r\n]*(?:\\[\w\W][^\\%\r\n]*)*\z

Посмотрите демонстрацию регулярного выражения .

Подробности

  • (?<!\\) - не разрешено \ сразу слева от текущего местоположения
  • (?:\\{2})* - любое количество двойных двойных косых черт (это и предыдущий шаблон необходимы, чтобы избежать совпадения с %, которому предшествует экранирующая обратная косая черта, вы не можете просто использовать (?<!\\))
  • % - % символ
  • [^\\%\r\n]* - ноль или более символов, кроме \, % и символов конца строки CR и LF
  • (?:\\[\w\W][^\\%\r\n]*)* - ноль или более вхождений
    • \\[\w\W] - любой экранированный символ, \\ соответствует \, а [\w\W] соответствует любому символу (его можно заменить на ., если вы добавите встроенный флаг (?s) DOTALL в начале шаблона)
    • [^\\%\r\n]* - любой ноль или более символов, кроме \, % и символов конца строки CR и LF.

В Java используйте шаблон, например

String text = "(a) last line % now with comment\n(b) last line with escaped \\%  and not treated\n(c) last line withouth any special chars\n(d) last line terminates with %\n(e) last line terminates with escaped \\%\n(f) beginning % but even escaped \\% is ignored";
Pattern p = Pattern.compile("(?<!\\\\)(?:\\\\{2})*%[^\\\\%\r\n]*(?:\\\\[\\w\\W][^\\\\%\r\n]*)*\\z");
Matcher m = p.matcher(text);
if (m.find()) {
  System.out.println("Match found!");
}
// => Match found!

Смотрите демонстрацию Java.

Спасибо - как уже упоминалось, это тот, который, кажется, требует наименьшей вычислительной мощности - в случае отсутствия попадания.

LeO 11.12.2020 20:53

Другие вопросы по теме