Мне нужна для 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) положительным, поскольку он соответствует последней строке.
Может ли кто-нибудь помочь, как отфильтровать только те %, которые я ищу?
Кроме того, мое предположение, что [^\\] нужен двойной экран, не соответствует ни одной строке. Хм... я что-то пропустил.
regex101.com/r/Yqpvb1/1 показывает правильное совпадение?
Или вам нужен regex101.com/r/Yqpvb1/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](?<!\\)%$ не работает. Я думал, что смогу инкапсулировать его для самой последней строки, но это не удается. Во всяком случае мне это нравится.
Вы можете использовать
(?<!\\)(?:\\{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.
Спасибо - как уже упоминалось, это тот, который, кажется, требует наименьшей вычислительной мощности - в случае отсутствия попадания.
Это все еще довольно расплывчато. Попробуйте
(?<!\\)(?:\\{2})*\\%[^\\\r\n]*(?:\\(?!%)[^\\\r\n]*)*\z, см. regex101.com/r/Yqpvb1/1