改进基于正则表达式的替换性能

时间:2013-10-14 12:27:07

标签: java regex string performance replaceall

大家好我想问一下流程所需的内存利用率和时间。我有以下代码。 我想优化我的代码,以便它更快。 字符串会占用更多内存吗?

public String replaceSingleToWord(String strFileText) {

    strFileText = strFileText.replaceAll("\\b(\\d+)[ ]?'[ ]?(\\d+)\"", "$1 feet $2  ");
    strFileText = strFileText.replaceAll("\\b(\\d+)[ ]?'[ ]?(\\d+)''", "$1 feet $2     inch");

    //for 23o34'
    strFileText = strFileText.replaceAll("(\\d+)[ ]?(degree)+[ ]?(\\d+)'", "$1 degree $3 second");

    strFileText = strFileText.replaceAll("(\\d+((,|.)\\d+)?)sq", " $1 sq");

    strFileText = strFileText.replaceAll("(?i)(sq. Km.)", " sqkm");
    strFileText = strFileText.replaceAll("(?i)(sq.[ ]?k.m.)", " sqkm");
    strFileText = strFileText.replaceAll("(?i)\\s(lb.)", " pound");
    //for pound
    strFileText = strFileText.replaceAll("(?i)\\s(am|is|are|was|were)\\s?:", "$1 ");
    return strFileText;
}

我认为这需要更多的内存和时间我只想减少复杂性。我只是想减少时间和内存来处理我需要做的更改。还有替换replaceAll函数吗?这段代码我将如何最小化?这样我的速度更快,内存利用率更低?先谢谢你了

4 个答案:

答案 0 :(得分:3)

优化方法:

  • 对每个替换使用Pattern.compile()。创建一个类,创建模式字段,并仅编译一次模式。这样可以节省大量时间,因为每次调用replaceAll()时都会进行正则表达式编译,这是一项非常昂贵的操作
  • 使用非贪婪的正则表达式。而不是(\\d+)使用(\\d+?)
  • 尽可能尝试不使用正则表达式(lb. - > pound)?
  • 将具有相同替换的多个正则表达式合并为一个 - 适用于您的sqkmfeet替换
  • 可以尝试将你的api基于StringBuilder;然后使用addReplacement处理您的文字。

此外,许多replace中的点都没有转义。点匹配任何字符。使用\\.

班级理念:

class RegexProcessor {
  private Pattern feet1rep = Pattern.compile("\\b(\\d+)[ ]?'[ ]?(\\d+)\"");
  // ...

  public String process(String org) {
    String mod = feet1rep.match(org).replaceAll("$1 feet $2  ");
    /...
  }
}

答案 1 :(得分:1)

当需要对字符串进行大量修改时,使用StringBuffer和StringBuilder类。

与StringBuffer类型的字符串对象不同,Stringbuilder可以反复修改而不会留下大量新的未使用对象。

StringBuilder类是从Java 5开始引入的,StringBuffer和StringBuilder之间的主要区别在于StringBuilders方法不是线程安全的(不是同步的)。

建议尽可能使用StringBuilder,因为它比StringBuffer更快。但是,如果需要线程安全性,最好的选择是StringBuffer对象。

public class Test{

    public static void main(String args[]){
       StringBuffer sBuffer = new StringBuffer(" test");
       sBuffer.append(" String Buffer");
       System.ou.println(sBuffer);  
   }
}




public class StringBuilderDemo {
    public static void main(String[] args) {
        String palindrome = "Dot saw I was Tod";

        StringBuilder sb = new StringBuilder(palindrome);

        sb.reverse();  // reverse it

        System.out.println(sb);
    }
}

因此根据您的需要,您可以选择其中一个。

参考http://docs.oracle.com/javase/tutorial/java/data/buffers.html

答案 2 :(得分:1)

使用预编译的Pattern和一个循环,就像Joop Eggen建议的那样。将表达式组合在一起。例如,前两个可以写成

`"\\b(\\d++) ?' ?(\\d+)(?:''|\")"`

您可以进一步牺牲可读性损失。您也可以使用单个表达式替换所有内容。

`"\\b(\\d++) ?(?:' ?(?:(\\d+)(?:''|\")|degree ?(\\d++)|...)"`

然后你需要在像group(2) == null这样的条件下进行分支。这很难维护,但是通过一个循环和巧妙编写的正则表达式,你将赢得比赛。 :d


  

单词的正则表达式如何不能 - > canot,不应该 - >不应该等等。

这取决于你想要的确切程度。最简单的方法是s.replaceAll("\\Bn't\\b", " not")。上述优化适用,因此在性能很重要时不要使用replaceAll

一般解决方案可以像这样

Pattern SHORTENED_WORD_PATTERN =
    Pattern.compile("\\b(ca|should|wo|must|might)(n't)\\b");

String getReplacement(String trunk) {
    switch (trunk) { // needs Java 7
        case "wo": return "will not";
        case "ca": return "cannot";
        default: return trunk + " not";
    }
}

... relevant part of the replacer loop (see [replaceAll][])

    while (matcher.find()) {
        matcher.appendReplacement(result, getReplacement(matcher.group(1)));
    }

  

如果是strFileText = strFileText.replace(“ÃÃ,¡”,“a”),我该怎么办? strFileText = strFileText.replace(“â™”,“\'”); strFileText = strFileText.replace(“â”,“\'”); strFileText = strFileText.replace(“ó”,“o”); strFileText = strFileText.replace(“é”,“e”); strFileText = strFileText.replace(“á”,“a”); strFileText = strFileText.replace(“ç”,“c”); strFileText = strFileText.replace(“ú”,“u”);如果我想用一行或其他方式写这个,那么对于那种情况,replaceEach()更好

如果您注意效率请注意,上述所有字符串都以相同的字符Ã开头。单个正则表达式可能á|’"|...Ã(ƒÂƒÃ‚¡|¢Â€Â™"|...)慢得多(除非正则表达式引擎可以自己优化它,目前情况并非如此)。

所以编写一个正则表达式,其中提取所有常见前缀并使用

String getReplacement(String match) {
    switch (match) { // needs Java 7
        case "á": return "a";
        case "’"": return "\\";
        ...
        default: throw new IllegalArgumentException("Unexpected: " + match);
    }
}

    while (matcher.find()) {
        matcher.appendReplacement(result, getReplacement(matcher.group()));
    }

也许HashMap可能比上面的switch更快。

答案 3 :(得分:0)

可以在spot_ [,.]?(而不是[ ]?)改进正则表达式模式。

在函数外部使用已编译的静态final Pattern

private static final Pattern PAT = Pattern.compile("...");


StringBuffer sb = new StringBuffer();
Matcher m = PAT.matcher(strFileText);
while (m.find()) {
    m.appendReplacement(sb, "...");
}
m.appendTail(sb);
strFileText = sb.toString();

在执行if (m.find)之前首先测试new StringBuffer可以进行优化。