文字列を置き換えるより良い方法はありますか?
Replaceが文字配列または文字列配列を取り込まないことに驚きました。私は自分自身の拡張機能を書くことができると思いますが、次のような方法で構築されたより良いものがあれば私は興味がありましたか?最後のReplaceは文字ではなく文字列です。
myString.Replace(';', '\n').Replace(',', '\n').Replace('\r', '\n').Replace('\t', '\n').Replace(' ', '\n').Replace("\n\n", "\n");
置換正規表現を使用できます。
s/[;,\t\r ]|[\n]{2}/\n/g
s/
は検索を意味します[
と]
の間の文字は、検索する文字です(任意の順序で)/
は、検索対象テキストと置換テキストを区切ります英語では、これは次のようになります。
「;
または,
または\t
または\r
または(スペース)または正確に2つの連続した\n
を検索し、それを\n
に置き換えてください。」
C#では、次のことができます。(System.Text.RegularExpressions
をインポートした後)
Regex pattern = new Regex("[;,\t\r ]|[\n]{2}");
pattern.Replace(myString, "\n");
あなたが特に賢く感じていてRegexを使いたくないのなら:
char[] separators = new char[]{' ',';',',','\r','\t','\n'};
string s = "this;is,\ra\t\n\n\ntest";
string[] temp = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);
s = String.Join("\n", temp);
これも、ほとんど手間をかけずに拡張メソッドでラップすることができます。
編集:またはちょうど2分待って、私はとにかくそれを書いてしまうでしょう:)
public static class ExtensionMethods
{
public static string Replace(this string s, char[] separators, string newVal)
{
string[] temp;
temp = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);
return String.Join( newVal, temp );
}
}
そして、ほら...
char[] separators = new char[]{' ',';',',','\r','\t','\n'};
string s = "this;is,\ra\t\n\n\ntest";
s = s.Replace(separators, "\n");
あなたはLinqのAggregate関数を使うことができます:
string s = "the\nquick\tbrown\rdog,jumped;over the lazy fox.";
char[] chars = new char[] { ' ', ';', ',', '\r', '\t', '\n' };
string snew = chars.Aggregate(s, (c1, c2) => c1.Replace(c2, '\n'));
これが拡張方法です。
public static string ReplaceAll(this string seed, char[] chars, char replacementCharacter)
{
return chars.Aggregate(seed, (str, cItem) => str.Replace(cItem, replacementCharacter));
}
拡張メソッドの使用例
string snew = s.ReplaceAll(chars, '\n');
これが最短の方法です:
myString = Regex.Replace(myString, @"[;,\t\r ]|[\n]{2}", "\n");
ああ、パフォーマンスホラー!答えは少し古くなっていますが、それでも...
public static class StringUtils
{
#region Private members
[ThreadStatic]
private static StringBuilder m_ReplaceSB;
private static StringBuilder GetReplaceSB(int capacity)
{
var result = m_ReplaceSB;
if (null == result)
{
result = new StringBuilder(capacity);
m_ReplaceSB = result;
}
else
{
result.Clear();
result.EnsureCapacity(capacity);
}
return result;
}
public static string ReplaceAny(this string s, char replaceWith, params char[] chars)
{
if (null == chars)
return s;
if (null == s)
return null;
StringBuilder sb = null;
for (int i = 0, count = s.Length; i < count; i++)
{
var temp = s[i];
var replace = false;
for (int j = 0, cc = chars.Length; j < cc; j++)
if (temp == chars[j])
{
if (null == sb)
{
sb = GetReplaceSB(count);
if (i > 0)
sb.Append(s, 0, i);
}
replace = true;
break;
}
if (replace)
sb.Append(replaceWith);
else
if (null != sb)
sb.Append(temp);
}
return null == sb ? s : sb.ToString();
}
}
あなたはそれを変更可能にする必要があります。
StringBuilder
を使用してunsafe
の世界に行き、ポインタで遊ぶ(しかし危険です)そして、最小の回数で文字の配列を反復するようにしてください。ここでHashSet
に注意してください。ループ内の文字シーケンスをトラバースするのを避けるためです。さらに高速な検索が必要な場合は、HashSet
を(array[256]
に基づく)char
の最適化された検索に置き換えることができます。
StringBuilderの例
public static void MultiReplace(this StringBuilder builder,
char[] toReplace,
char replacement)
{
HashSet<char> set = new HashSet<char>(toReplace);
for (int i = 0; i < builder.Length; ++i)
{
var currentCharacter = builder[i];
if (set.Contains(currentCharacter))
{
builder[i] = replacement;
}
}
}
編集 - 最適化バージョン
public static void MultiReplace(this StringBuilder builder,
char[] toReplace,
char replacement)
{
var set = new bool[256];
foreach (var charToReplace in toReplace)
{
set[charToReplace] = true;
}
for (int i = 0; i < builder.Length; ++i)
{
var currentCharacter = builder[i];
if (set[currentCharacter])
{
builder[i] = replacement;
}
}
}
それならあなたはこれを次のように使うだけです:
var builder = new StringBuilder("my bad,url&slugs");
builder.MultiReplace(new []{' ', '&', ','}, '-');
var result = builder.ToString();
単に 文字列拡張メソッド と書いて、それらをあなたの解決策のどこかに置くこともできます。
using System.Text;
public static class StringExtensions
{
public static string ReplaceAll(this string original, string toBeReplaced, string newValue)
{
if (string.IsNullOrEmpty(original) || string.IsNullOrEmpty(toBeReplaced)) return original;
if (newValue == null) newValue = string.Empty;
StringBuilder sb = new StringBuilder();
foreach (char ch in original)
{
if (toBeReplaced.IndexOf(ch) < 0) sb.Append(ch);
else sb.Append(newValue);
}
return sb.ToString();
}
public static string ReplaceAll(this string original, string[] toBeReplaced, string newValue)
{
if (string.IsNullOrEmpty(original) || toBeReplaced == null || toBeReplaced.Length <= 0) return original;
if (newValue == null) newValue = string.Empty;
foreach (string str in toBeReplaced)
if (!string.IsNullOrEmpty(str))
original = original.Replace(str, newValue);
return original;
}
}
彼らをこのように呼ぶ:
"ABCDE".ReplaceAll("ACE", "xy");
xyBxyDxy
この:
"ABCDEF".ReplaceAll(new string[] { "AB", "DE", "EF" }, "xy");
xyCxyF
次のようなRegEx.Replaceを使用してください。
string input = "This is text with far too much " +
"whitespace.";
string pattern = "[;,]";
string replacement = "\n";
Regex rgx = new Regex(pattern);
これについての詳細はこちら--- RegEx.ReplaceのためのMSDNドキュメント
string ToBeReplaceCharacters = @"~()@#$%&+,'"<>|;\/*?";
string fileName = "filename;with<bad:separators?";
foreach (var RepChar in ToBeReplaceCharacters)
{
fileName = fileName.Replace(RepChar.ToString(), "");
}
パフォーマンス的には、これはおそらく最良の解決策ではないかもしれませんが、うまくいきます。
var str = "filename:with&bad$separators.txt";
char[] charArray = new char[] { '#', '%', '&', '{', '}', '\\', '<', '>', '*', '?', '/', ' ', '$', '!', '\'', '"', ':', '@' };
foreach (var singleChar in charArray)
{
str = str.Replace(singleChar, '_');
}