【问题标题】:Replace a set of substring in a string in more efficient way?以更有效的方式替换字符串中的一组子字符串?
【发布时间】:2014-11-12 21:06:24
【问题描述】:

我必须用另一个子字符串替换字符串中的一组子字符串,例如

  1. "^t""\t"
  2. "^=""\u2014"
  3. "^+""\u2013"
  4. "^s""\u00A0"
  5. "^?""."
  6. "^#""\\d"
  7. "^$""[a-zA-Z]"

所以,我尝试过:

String oppip = "pippo^t^# p^+alt^shefhjkhfjkdgfkagfafdjgbcnbch^";

Map<String,String> tokens = new HashMap<String,String>();
tokens.put("^t", "\t");
tokens.put("^=", "\u2014");
tokens.put("^+", "\u2013");
tokens.put("^s", "\u00A0");
tokens.put("^?", ".");
tokens.put("^#", "\\d");
tokens.put("^$", "[a-zA-Z]");

String regexp = "^t|^=|^+|^s|^?|^#|^$";

StringBuffer sb = new StringBuffer();
Pattern p = Pattern.compile(regexp);
Matcher m = p.matcher(oppip);
while (m.find())
    m.appendReplacement(sb, tokens.get(m.group()));
m.appendTail(sb);
System.out.println(sb.toString()); 

但它不起作用。 tokens.get(m.group()) 抛出异常。

知道为什么吗?

【问题讨论】:

  • tokens.get(m.group()) 抛出什么异常?你能给出完整的异常堆栈跟踪吗?
  • 对不起。我忘了。空指针异常

标签: java regex string


【解决方案1】:

在正则表达式中,^ 表示“文本开头”(或字符类中的“非”作为否定)。您必须在它之前放置一个反斜杠,这将成为 java 字符串中的两个反斜杠。

String regexp = "\\^[t=+s?#$]";

我已经减少了一点。

【讨论】:

    【解决方案2】:

    您不必使用HashMap。考虑使用简单数组和循环

    String oppip = "pippo^t^# p^+alt^shefhjkhfjkdgfkagfafdjgbcnbch^";
    
    String[] searchFor =
    {"^t", "^=", "^+", "^s", "^?", "^#", "^$"},
             replacement =
    {"\\t", "\\u2014", "\\u2013", "\\u00A0", ".", "\\d", "[a-zA-Z]"};
    
    for (int i = 0; i < searchFor.length; i++)
        oppip = oppip.replace(searchFor[i], replacement[i]);
    
    // Print the result.
    System.out.println(oppip);
    

    这是online code demo


    为了完整起见,您可以使用二维数组进行类似的方法:

    String oppip = "pippo^t^# p^+alt^shefhjkhfjkdgfkagfafdjgbcnbch^";
    
    String[][] tasks =
    {
        {"^t", "\\t"},
        {"^=", "\\u2014"}, 
        {"^+", "\\u2013"}, 
        {"^s", "\\u00A0"}, 
        {"^?", "."}, 
        {"^#", "\\d"}, 
        {"^$", "[a-zA-Z]"}
    };
    
    for (String[] replacement : tasks)
        oppip = oppip.replace(replacement[0], replacement[1]);
    
    // Print the result.
    System.out.println(oppip);
    

    【讨论】:

    • 我认为您的意思是 replaceAll(...) 不是 replace(...),但除此之外,我喜欢这个解决方案。不要试图一次做所有的替换,一次做一个,代码会简单得多。
    • @IanMcLaird .replaceAll 采用正则表达式。 .replace() takes a string and it's literal,所以不用转义了。
    • @IanMcLaird replaceAll 使用正则表达式,而 OP 显然想要替换文字,所以 replace 在这里更好。但是如果可以像a-&gt;bb-&gt;a那样存在循环替换,则可能存在问题。在这种情况下,通过将所有a 替换为b,然后将所有b 替换为a,我们最终只能得到aappendReplacementappendTail 解决了这个问题。
    • Matt3o 的方法确实有一个优点,即只需要一次匹配通过原始字符串,并且只需要一次字符串分配。此答案中的方法需要 N 次匹配通过,其中 N 是替换目标的数量。当 N 很小(几乎可以肯定)时,这种方法会更快,但这是一种“Schlemiel the Painter”算法。
    • @Unihedron 您的答案中的方法将需要为每个替换迭代整个字符串,而 OP 代码不必检查正则表达式描述的所有模式,但会在它可以使用的第一个模式处停止,所以如果它会在X 位置找到"^t" 它不会测试^=|^+|^s|^?|^#|^$ 是否有其他可能性,因此X 位置的子字符串只会被测试一次。在最坏的情况下,它必须测试直到最后一个^$ 的组合。因此,您的答案中的代码与 OP 代码的最坏情况相同(这很好,因为它是干净的代码,但效率在于正则表达式方面)。
    猜你喜欢
    • 2010-11-22
    • 2012-04-26
    • 2012-04-03
    • 2013-07-23
    • 2012-01-05
    相关资源
    最近更新 更多