3

単語を指定すると、特定のアルファベットを、a の場合は 1、b の場合は 5 などの特定の文字に置き換える必要があります。これには正規表現を使用しています。私は多くの文字列操作を行っているため、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

私はあなたができるとは思わない。すべての正規表現置換 API は、StringBuilder の代わりに String を使用します。

基本的に各文字を別の文字に変換する場合は、次のようにすることができます。

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 がここでのツールであるかどうかはわかりません。Java 正規表現パッケージの一部であり、本当にパフォーマンスが必要な場合は、上記の例よりも高速になる可能性があるMatcherを検討することを検討します。

于 2008-11-11T19:46:05.583 に答える
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() が間違ったツールである理由は、呼び出すたびに正規表現をコンパイルして文字列全体を処理しているためです。次のように、すべての正規表現を 1 つに結合し、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 に答える