web-dev-qa-db-ja.com

C#で複数の文字列要素を置き換える

これを行うより良い方法はありますか...

MyString.Trim().Replace("&", "and").Replace(",", "").Replace("  ", " ")
         .Replace(" ", "-").Replace("'", "").Replace("/", "").ToLower();

文字列クラスを拡張して1つのジョブに限定しましたが、もっと簡単な方法はありますか?

public static class StringExtension
{
    public static string clean(this string s)
    {
        return s.Replace("&", "and").Replace(",", "").Replace("  ", " ")
                .Replace(" ", "-").Replace("'", "").Replace(".", "")
                .Replace("eacute;", "é").ToLower();
    }
}

ただの楽しみのために(そしてコメントの議論を止めるために)、以下のさまざまな例をベンチマークする要点を突きつけました。

https://Gist.github.com/ChrisMcKee/5937656

正規表現オプションのスコアはひどいものです。辞書オプションが最速になります。文字列ビルダーの長い巻き上げバージョンは、ショートハンドよりもわずかに高速です。

73
Chris McKee

より速く-いいえ。より効果的-はい、StringBuilderクラスを使用する場合。実装では、各操作によって文字列のコピーが生成され、状況によってはパフォーマンスが低下する可能性があります。文字列は不変オブジェクトなので、各操作は変更されたコピーを返すだけです。

このメソッドがかなりの長さの複数のStringsでアクティブに呼び出されると予想される場合、その実装をStringBuilderクラスに「移行」することをお勧めします。これにより、変更はそのインスタンスで直接実行されるため、不要なコピー操作を省くことができます。

public static class StringExtention
{
    public static string clean(this string s)
    {
        StringBuilder sb = new StringBuilder (s);

        sb.Replace("&", "and");
        sb.Replace(",", "");
        sb.Replace("  ", " ");
        sb.Replace(" ", "-");
        sb.Replace("'", "");
        sb.Replace(".", "");
        sb.Replace("eacute;", "é");

        return sb.ToString().ToLower();
    }
}
105
user151323

多分もう少し読みやすい?

    public static class StringExtension {

        private static Dictionary<string, string> _replacements = new Dictionary<string, string>();

        static StringExtension() {
            _replacements["&"] = "and";
            _replacements[","] = "";
            _replacements["  "] = " ";
            // etc...
        }

        public static string clean(this string s) {
            foreach (string to_replace in _replacements.Keys) {
                s = s.Replace(to_replace, _replacements[to_replace]);
            }
            return s;
        }
    }

また、StringBuilderについてNew In Townの提案を追加...

13
Paolo Tedesco

これはより効率的です:

public static class StringExtension
{
    public static string clean(this string s)
    {
        return new StringBuilder(s)
              .Replace("&", "and")
              .Replace(",", "")
              .Replace("  ", " ")
              .Replace(" ", "-")
              .Replace("'", "")
              .Replace(".", "")
              .Replace("eacute;", "é")
              .ToString()
              .ToLower();
    }
}
11
TheVillageIdiot

単にかなりの解決策を求めていて、数ナノ秒を節約する必要がない場合、LINQ砂糖はどうですか?

var input = "test1test2test3";
var replacements = new Dictionary<string, string> { { "1", "*" }, { "2", "_" }, { "3", "&" } };

var output = replacements.Aggregate(input, (current, replacement) => current.Replace(replacement.Key, replacement.Value));
10
TimS

提案されたソリューションで最適化できるものが1つあります。 Replace()を何度も呼び出すと、コードは同じ文字列に対して複数のパスを実行します。非常に長い文字列では、CPUキャッシュ容量が不足するため、ソリューションが遅くなる場合があります。 1回のパスで複数の文字列を置き換える を考慮する必要があります。

4
Andrej Adamenko

私は似たようなことをしていますが、私の場合はシリアライゼーション/デシリアライゼーションをしていますので、両方向に行くことができる必要があります。 string [] []を使用すると、初期化を含め、辞書とほぼ同じように機能しますが、元の値に置換を戻すこともできます。辞書は実際には設定されていません。

編集:string [] []と同じ結果を得るためにDictionary<Key,List<Values>>を使用できます

2
sidDemure

Linqを使用する別のオプションは

[TestMethod]
public void Test()
{
  var input = "it's worth a lot of money, if you can find a buyer.";
  var expected = "its worth a lot of money if you can find a buyer";
  var removeList = new string[] { ".", ",", "'" };
  var result = input;

  removeList.ToList().ForEach(o => result = result.Replace(o, string.Empty));

  Assert.AreEqual(expected, result);
}
2
Luiz Felipe