Java regex - стирать символы, за которыми следует \b (backspace)

У меня есть строка, построенная из типов пользовательских клавиатур, поэтому она может содержать символы '\b' (обратные области).

Я хочу очистить строку, чтобы она не содержала символы '\b', а также символы, которые они должны стереть. Например, строка:

String str = "\bHellow\b world!!!\b\b\b.";

Должен быть напечатан как:

Hello world.

Я попробовал несколько вещей с replaceAll, и теперь у меня есть:

System.out.println(str.replaceAll("^\b+|.\b+", ""));

Какие принты:

Привет, мир!!.

Одиночный '\b' обрабатывается отлично, но его кратность игнорируется.

Итак, могу ли я решить его с помощью Java regex?

EDIT:

Я видел этот ответ, но, похоже, это не относится к java replaceAll.
Может быть, я пропускаю что-то со стенографической строкой...

Ответ 1

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

Это задание (это всего две небольшие строки):

while (str.contains("\b"))
    str = str.replaceAll("^\b+|[^\b]\b", "");

Это обрабатывает кромку ввода типа "x\b\by", у которой есть дополнительное backspace в начале, которое должно быть обрезано, когда первый потребляет x, оставив только "y".

Ответ 2

Это выглядит как работа для Stack!

Stack<Character> stack = new Stack<Character>();

// for-each character in the string
for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);

    // push if it not a backspace
    if (c != '\b') {
        stack.push(c);
    // else pop if possible
    } else if (!stack.empty()) {
        stack.pop();
    }
}

// convert stack to string
StringBuilder builder = new StringBuilder(stack.size());

for (Character c : stack) {
    builder.append(c);
}

// print it
System.out.println(builder.toString());

Regex, хотя и хорошо, не подходит для каждой задачи. Этот подход не так лаконичен, как богемский, но он более эффективен. Использование стека - это O (n) в каждом случае, в то время как подход с регулярным выражением, такой как богемский, равен O (n 2) в худшем случае.

Ответ 3

Проблема, которую вы пытаетесь решить, не может быть решена с помощью регулярного выражения single. Проблема в том, что грамматика, которая генерирует язык {any_symbol}*{any_symbol}^n{\b}^n (который является частным случаем вашего ввода), не является regular. Вам нужно сохранить состояние где-нибудь (сколько символов перед \b и \b, которое оно прочитало), но DFA не может этого сделать (потому что DFA не может знать, сколько последовательных \b он может найти). Все предлагаемые решения представляют собой просто регулярные выражения для вашего случая ("\bHellow\b world!!!\b\b\b.") и могут быть легко разбиты с более сложным тестом.

Самое простое решение для вашего дела заменяется на пару циклов {all except\b} {\ b}

UPD: Решение, предложенное @Bohemian, кажется совершенно правильным:

UPD 2: Похоже, что java regexes может анализировать не только обычные языки, но также вводить как {a}^n{b}^n с рекурсивным lookahead, поэтому в случае java можно сопоставить группы с одиночными регулярное выражение. Спасибо за комментарии @Pshemo и правки @Elist!

Ответ 4

Если я правильно понимаю вопрос, это решение вашего вопроса:

String str = "\bHellow\b world!!!\b\b\b.";
System.out.println(str.replace(".?\\\b", ""));

Ответ 5

Это была приятная загадка. Я думаю, вы можете использовать regex , чтобы удалить одинаковое количество одинаковых повторяющихся символов и \b s (т.е. Для вашей конкретной строки ввода):

String str = "\bHellow\b world!!!\b\b\b.";
System.out.println(str.replaceAll("^\b+|(?:([^\b])(?=\\1*+(\\2?+\b)))+\\2", ""));

Это адаптация Как мы можем сопоставить a ^ n b ^ n с Java regex?.

Смотрите демонстрацию IDEONE, где я добавил .replace("\b","<B>"));, чтобы увидеть, есть ли \b слева.

Вывод:

Hello world.

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