【问题标题】:Java regex - erase characters followed by \b (backspace)Java 正则表达式 - 擦除字符后跟 \b(退格)
【发布时间】:2015-09-22 05:57:59
【问题描述】:

我有一个由用户键盘类型构成的字符串,因此它可能包含'\b' 字符(退格)。

我想清理字符串,使其不包含'\b' 字符以及它们要删除的字符。例如,字符串:

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

应该打印为:

Hello world.

我已经用replaceAll尝试了一些东西,我现在拥有的是:

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

哪些打印:

世界你好!!。

单个'\b' 处理得很好,但它的倍数被忽略。

那么,我可以用 Java 的正则表达式解决它吗?

编辑:

看过this的回答,但是好像不适用于java的replaceAll。
也许我在逐字字符串中遗漏了一些东西......

【问题讨论】:

  • 您如何打印此字符串以在输出中获得\b
  • Eclipse 的控制台......但我也在 XML-RPC 中传递它,但它失败了,因为它是一个无效的 XML 字符......
  • 我只是在我的 Eclipse 控制台上看到 Hellow world!!!.,而没有显示 \b
  • 可能需要将控制台编码设置为UTF8。无论如何,您可以调试和检查字符串。
  • 看起来您正在匹配A(n)B(n) 字符串,所以here 是一个相关问题,其中有一个很长的答案来解释要做什么。

标签: java regex


【解决方案1】:

除非对连续退格的数量有实际限制(没有),并且可以保证(没有)没有“额外" 没有要删除的前导字符的退格。

这样就可以了(它只有 2 条小线):

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

这会处理像"x\b\by" 这样的输入的边缘情况,它在开始时有一个额外的退格,一旦第一个使用x,就应该修剪它,只留下"y"

【讨论】:

  • 谢谢,我会采用这种方法。会接受这个答案(如果没有其他人有一个神奇的纯正则表达式来击败这个......)
  • 它只需要一个简单的修复。如果输入是\bbbbbHellow\b world!!!\b\b\b.,它会得到Hello world!!.的结果,我认为这不是预期的,应该给我们一个bbbbHello world!!.的输出。只需删除开头的量词或将\b 设为一个组。
  • @GarisMSuero - 您的示例按预期打印bbbbHello world.
  • @GarisMSuero 我不确定你的意思。您的示例产生bbbbHello world.,这似乎是有效的ideone.com/SlCuW7
  • @Pshemo @elist 抱歉我的困惑。我还是不知道这种情况下量词+有什么用。
【解决方案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's 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());

正则表达式虽然不错,但并不适合所有任务。这种方式不如Bohemian's简洁,但是效率更高。在每种情况下使用堆栈都是 O(n),而像 Bohemian 的正则表达式方法在最坏的情况下是 O(n2)。

【讨论】:

  • 显然,堆栈是这里的终极解决方案,但我一直在寻找一种快速且“内联”的方法来解决这个问题。我还学到了一些不错的正则表达式技巧...
  • @Luke 和 Elist,我喜欢这个解决方案,但是当只是“让事情正常工作”时,你可以用几乎没有代码的正则表达式来做这件事真是太棒了——这是一项值得学习的技能。而且它的性能也不错——肯定不是纳秒快,但是对replaceAll() 的典型调用只需要几微秒;它“足够快”,如果您需要从应用中获得更多性能,您可以快速继续编写其余代码并稍后重新访问。
【解决方案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的正则表达式可以解析not only regular languages,但也可以使用递归前瞻来解析{a}^n{b}^n之类的输入,因此对于java,可以使用单个正则表达式匹配这些组。 感谢@Pshemo cmets 和@Elist 编辑!

【讨论】:

  • 我怀疑这可以用正则表达式来完成,但是这个正则表达式非常不可读,所以最好创建我们自己的解析器。
  • 我再次参考我编辑中提到的 C# 示例:stackoverflow.com/a/16604714/1609201。 Java中有类似物吗?如果不是,这两种语言的正则表达式功能有什么区别?
  • 现在即使使用这个 Java 正则表达式:stackoverflow.com/questions/3644266/… 大约是 a^n b^n?
  • 似乎我不知道所有 Java 正则表达式的可能性。看起来 java 的正则表达式不仅可以解析常规语言,还可以将 a^n b^n 之类的输入与递归前瞻匹配,因此答案是“有可能”(但请注意大型输入的 StackOverflowError)
【解决方案4】:

如果我正确理解了这个问题,这就是您问题的解决方案:

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

【讨论】:

  • 你没有。他想在找到的每个/b 上模拟退格删除键。
【解决方案5】:

这是一个很好的谜语。我认为您可以使用正则表达式删除相同数量的相同重复字符和\bs(即对于您的特定输入字符串):

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

这是对How can we match a^n b^n with Java regex?的改编。

查看IDEONE demo,我在其中添加了.replace("\b","&lt;B&gt;"));,看看是否还有\b

输出:

Hello world.

目前,仅通用正则表达式的解决方案超出了正则表达式的范围。

【讨论】:

  • 字符串本身包含'.',模式没有
  • 是的,这就是我从模式中删除它的原因。
  • 有趣,但仍然打印 Hellow\b world。在我的控制台中
  • 尝试将输入字符串中的! 更改为x,看看会发生什么。 (-1)
  • @Bohemian:我已经通过修改“a^n b^n”正则表达式来编辑答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
  • 2013-06-30
  • 2016-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多