3

给定一个词,我必须用一些特定的字母替换一些特定的字母,例如 1 代表 a,5 代表 b 等。我为此使用正则表达式。我知道 StringBuilder 是处理这个问题的最好方法,因为我正在做很多字符串操作。这是我正在做的事情:

String word = "foobooandfoo";
String converted = "";
converted = word.replaceAll("[ao]", "1");
converted = converted.replaceAll("[df]", "2");
converted = converted.replaceAll("[n]", "3");

我的问题是如何使用 StringBuilder 重写这个程序。我尝试了一切,但我无法成功。或者使用 String 就可以了?

4

9 回答 9

8

我认为这是一个清晰和性能完美契合的案例。我会使用查找表来进行“翻译”。

  public static void translate(StringBuilder str, char[] table)
  {
    for (int idx = 0; idx < str.length(); ++idx) {
      char ch = str.charAt(idx);
      if (ch < table.length) {
        ch = table[ch];
        str.setCharAt(idx, ch);
      }
    }
  }

如果str输入的字母很大,或者映射稀疏,则可以使用真实的映射,如下所示:

  public static void translate(StringBuilder str, Map<Character, Character> table)
  {
    for (int idx = 0; idx < str.length(); ++idx) {
      char ch = str.charAt(idx);
      Character conversion = table.get(ch);
      if (conversion != null) 
        str.setCharAt(idx, conversion);
    }
  }

虽然这些实现就地工作,但您可以创建一个新StringBuilder实例(或附加到传入的实例)。

于 2008-11-11T19:59:43.093 回答
2

我实际上会说代码在大多数应用程序中都很好,尽管它在理论上不如其他方法。如果您不想使用Matcher,请尝试如下:

StringBuilder result = new StringBuilder(word.length());

for (char c : word.toCharArray()) {
    switch (c) {
        case 'a': case 'o': result.append('1'); break;
        case 'd': case 'f': result.append('2'); break;
        case 'n': result.append('3'); break;
        default: result.append(c); break;
    }
}
于 2008-11-11T19:49:32.630 回答
1

我不知道 StringBuilder 是否适合您。我会考虑查看Matcher ,它是 java regex 包的一部分,如果你真的需要性能,它可能比你上面的例子更快。

于 2008-11-11T19:46:05.583 回答
1

我不相信你可以。所有正则表达式替换 API 都使用 String 而不是 StringBuilder。

如果您基本上是将每个字符转换为不同的字符,则可以执行以下操作:

public String convert(String text)
{
    char[] chars = new char[text.length()];
    for (int i=0; i < text.length(); i++)
    {
        char c = text.charAt(i);
        char converted;
        switch (c)
        {
            case 'a': converted = '1'; break;
            case 'o': converted = '1'; break;
            case 'd': converted = '2'; break;
            case 'f': converted = '2'; break;
            case 'n': converted = '3'; break;
            default : converted = c; break;
        }
        chars[i] = converted;
    }
    return new String(chars);
}

但是,如果您执行任何复杂的正则表达式,那显然不会有太大帮助。

于 2008-11-11T19:50:06.327 回答
1

StringBuilder 和 StringBuffer 在某些程序中可能会有很大的性能差异。请参阅:http ://www.thectoblog.com/2011/01/stringbuilder-vs-stringbuffer-vs.html 这将是坚持下去的一个强有力的理由。

原始帖子要求将多字符替换为单个字符。这会影响调整大小,进而影响性能。

也就是说,最简单的方法是使用字符串。但是如果性能是一个问题,要注意它是否可以最大限度地减少 gc 和其他影响。

我喜欢 P Arrayah 的方法,但对于更通用的答案,它应该使用 LinkedHashMap 或保留顺序的东西,以防替换具有依赖性。

Map replaceRules = new HashMap();

Map replaceRules = new LinkedHashMap();

于 2011-09-13T14:35:03.537 回答
0

我看了看,Matcher.replaceAll()我注意到它返回一个String. 因此,我认为你所拥有的将会非常快。正则表达式易于阅读且快速。

记住优化的第一条规则:不要这样做!

于 2008-11-11T19:49:23.207 回答
0

我知道 StringBuilder 是处理这个问题的最好方法,因为我正在做很多字符串操作。

谁对你这么说的?最好的方法是那些更容易阅读的方法,使用 StringBuilder 的方法。StringBuilder 在某些情况下,但在许多情况下并没有提供明显的加速。

如果值总是被替换,则不应初始化“已转换”。

您可以删除一些样板来改进您的代码:

String word = "foobooandfoo";
String converted = word.replaceAll("[ao]", "1")
                       .replaceAll("[df]", "2")
                       .replaceAll("[n]", "3");

如果你想使用 StringBuilder 你可以使用这个方法

java.util.regex.Pattern#matcher(java.lang.CharSequence)

它接受 CharSequence(由 StringBuilder 实现)。请参阅http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html#matcher(java.lang.CharSequence)

于 2008-11-11T20:21:09.693 回答
0

StringBuilder 与 regex 是错误的二分法。String#replaceAll() 是错误工具的原因是,每次调用它时,您都在编译正则表达式并处理整个字符串。您可以通过将所有正则表达式组合为一个并使用 Matcher 中的低级方法而不是 replaceAll() 来避免所有多余的工作,如下所示:

String text = "foobooandfoo";
Pattern p = Pattern.compile("([ao])|([df])|n");
Matcher m = p.matcher(text);
StringBuffer sb = new StringBuffer();
while (m.find())
{
  m.appendReplacement(sb, "");
  sb.append(m.start(1) != -1 ? '1' :
            m.start(2) != -1 ? '2' :
                               '3');
}
m.appendTail(sb);
System.out.println(sb.toString());

当然,这仍然是大材小用;对于这样简单的工作,我推荐埃里克森的方法。

于 2008-11-12T10:44:59.653 回答
-2

我不建议为此使用任何正则表达式,当您进行简单操作时,这些实际上都非常缓慢。相反,我建议你从这样的事情开始

// usage:
Map<String, String> replaceRules = new HashMap<String, String>();
replaceRules.put("ao", "1");
replaceRules.put("df", "2");
replaceRules.put("n", "3");
String s = replacePartsOf("foobooandfoo", replaceRules);

// actual method
public String replacePartsOf(String thisString, Map<String, String> withThese) {
    for(Entry<String, String> rule : withThese.entrySet()) {
        thisString = thisString.replaceAll(rule.getKey(), rule.getValue());
    }

    return thisString;
}

在你完成这个工作之后,将它重构为使用字符数组。虽然我认为您想要做的事情可以使用 StringBuilder 完成,但很可能不值得付出努力。

于 2008-11-11T20:57:58.920 回答