1. ホーム
  2. c#

[解決済み】文字列から特殊文字を削除する最も効率的な方法

2022-03-30 10:31:34

質問

ある文字列から特殊文字をすべて削除したい。使用できる文字は、A-Z(大文字または小文字)、数字(0-9)、アンダースコア(_)、ドット記号(...)です。

私は次のようなものを持っています、それは動作しますが、私はそれが非常に効率的ではないことを疑う(私は知っている!)。

    public static string RemoveSpecialCharacters(string str)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.Length; i++)
        {
            if ((str[i] >= '0' && str[i] <= '9')
                || (str[i] >= 'A' && str[i] <= 'z'
                    || (str[i] == '.' || str[i] == '_')))
                {
                    sb.Append(str[i]);
                }
        }

        return sb.ToString();
    }

最も効率的な方法は何でしょうか?正規表現はどのようなもので、通常の文字列操作と比較してどうなのでしょうか?

クリーニングされる文字列は、通常10文字から30文字程度の短いものです。

解決方法

なぜ、その方法は効率的でないと思うのですか?実は、最も効率的な方法の一つなんです。

もちろん、その文字をローカル変数に読み込んだり、配列へのアクセス回数を減らすためにエニュメレータを使用する必要があります。

public static string RemoveSpecialCharacters(this string str) {
   StringBuilder sb = new StringBuilder();
   foreach (char c in str) {
      if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_') {
         sb.Append(c);
      }
   }
   return sb.ToString();
}

このようなメソッドが効率的なのは、スケールが良いということです。実行時間は文字列の長さに対して相対的なものになります。大きな文字列で使っても、驚くようなことはない。

編集する

24文字の文字列で各関数を100万回実行し、簡単な性能テストをしてみました。その結果がこれだ。

オリジナル関数です。54.5ミリ秒

私の提案した変更点 47.1ms。

StringBuilderの容量を設定した場合の私:43.3ms。

正規表現:294.4ms

編集2 上のコードにA-Zとa-zの区別を追加しました。(パフォーマンステストを再実行しましたが、目立った違いはありません)。

編集3

lookup+char[]の解決策をテストしてみたところ、約13msで実行されました。

その代償は、もちろん、巨大なルックアップテーブルの初期化とメモリへの保持です。まあ、それほど大きなデータ量ではないのですが、こんなつまらない関数にしては多いですね...。

private static bool[] _lookup;

static Program() {
   _lookup = new bool[65536];
   for (char c = '0'; c <= '9'; c++) _lookup[c] = true;
   for (char c = 'A'; c <= 'Z'; c++) _lookup[c] = true;
   for (char c = 'a'; c <= 'z'; c++) _lookup[c] = true;
   _lookup['.'] = true;
   _lookup['_'] = true;
}

public static string RemoveSpecialCharacters(string str) {
   char[] buffer = new char[str.Length];
   int index = 0;
   foreach (char c in str) {
      if (_lookup[c]) {
         buffer[index] = c;
         index++;
      }
   }
   return new string(buffer, 0, index);
}