Регулярное выражение для соответствия только неэпизованным специальным символам

Я пытаюсь найти регулярное выражение, которое может соответствовать только символам, которым не предшествует специальная escape-последовательность в строке.

Например, в строке Is ? stranded//? я хочу иметь возможность заменить ?, который не был экранирован с другой строкой, поэтому я могу получить этот результат: **Is Dave stranded?**

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

Как вы создаете регулярное выражение, которое соответствует только символам, которым не предшествует escape-последовательность?

Ответы

Ответ 1

Попробуйте этот код Java:

str="Is ? stranded//?";
Pattern p = Pattern.compile("(?<!//)([?])");
m = p.matcher(str);
StringBuffer sb = new StringBuffer();
while (m.find()) {
    m.appendReplacement(sb, m.group(1).replace("?", "Dave"));
}
m.appendTail(sb);
String s = sb.toString().replace("//", "");
System.out.println("Output: " + s);

OUTPUT

Output: Is Dave stranded?

Ответ 2

Используйте отрицательный lookbehind, это то, что они предназначены для создания!

(<?!//) [? \]

Чтобы остановить его:

(
    ?<!    #The negative look behind.  It will check that the following slashes do not exist.
    //     #The slashes you are trying to avoid.
)
[\?]       #Your special charactor list.

Только если//не может быть найден, он будет работать с остальной частью поиска.

Я думаю, что в Java ему нужно будет снова экранировать как строку, например:

Pattern p = Pattern.compile("(?<!//)[\\?]");

Ответ 3

Используйте группировку. Вот один пример:

import java.util.regex.*;

class Test {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("([^/][^/])(\\?)");
        String s = "Is ? stranded//?";
        Matcher m = p.matcher(s);
        if (m.matches)
            s = m.replaceAll("$1XXX").replace("//", "");
        System.out.println(s + " -> " + s);
    }
}

Вывод:

$ java Test
Is ? stranded//? -> Is XXX stranded?

В этом примере я:

  • первая замена любого неэкспериментированного? с "XXX",
  • затем удалив escape-последовательности "//".

EDIT Используйте if (m.matches), чтобы убедиться, что вы неправильно обрабатываете строки, не соответствующие друг другу.

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

Ответ 4

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

String input = "Is ? stranded//?"; 
String output = input
    .replace("//?", "a717efbc-84a9-46bf-b1be-8a9fb714fce8")
    .replace("?", "Dave")
    .replace("a717efbc-84a9-46bf-b1be-8a9fb714fce8", "?");

Просто защитите "//?" заменив его чем-то уникальным (например, guid). Тогда вы знаете, что любые оставшиеся вопросительные знаки являются честной игрой.

Ответ 5

Совпадение по набору символов, отличных от escape-последовательности, затем специальный символ регулярного выражения. Вы можете использовать инвертированный класс символов ([^/]) для первого бита. Особым случаем является неэкранированный символ регулярного выражения в начале строки.

Ответ 6

попробуйте сопоставить:

(^|(^.)|(.[^/])|([^/].))[special characters list]

Ответ 7

String aString = "Is ? stranded//?";

String regex = "(?<!//)[^a-z^A-Z^\\s^/]";
System.out.println(aString.replaceAll(regex, "Dave"));

Часть регулярного выражения [^a-z^A-Z^\\s^/] соответствует не-буквенно-цифровым символам, пробелам или непересылаемым символам косой черты.

Часть (?<!//) делает отрицательный lookbehind - см. docco здесь для получения дополнительной информации

Это дает выход Is Dave stranded//?