有没有更好的方法来替换字符串?

我很惊讶Replace不接受字符数组或字符串数组。我想我可以写我自己的扩展,但我很好奇是否有更好的内置方式来做以下工作?注意最后一个Replace是一个字符串而不是字符。

myString.Replace(';', '\n').Replace(',', '\n').Replace('\r', '\n').Replace('\t', '\n').Replace(' ', '\n').Replace("\n\n", "\n");

当前回答

在构建了自己的解决方案并查看这里使用的解决方案后,我利用了一个不使用复杂代码且通常对大多数参数有效的答案。

Cover base cases where other methods are more appropriate. If there are no chars to replacement, return the original string. If there is only one, just use the Replace method. Use a StringBuilder and initialize the capacity to the length of the original string. After all, the new string being built will have the same length of the original string if its just chars being replaced. This ensure only 1 memory allocation is used for the new string. Assuming that the 'char' length could be small or large will impact performance. Large collections are better with hashsets, while smaller collections are not. This is a near-perfect use case for Hybrid Dictionaries. They switch to using a Hash based lookup once the collection gets too large. However, we don't care about the value of the dictionary, so I just set it to "true". Have different methods for StringBuilder verse just a string will prevent unnecessary memory allocation. If its just a string, don't instantiate a StringBuilder unless the base cases were checked. If its already a StringBuilder, then perform the replacements and return the StringBuilder itself (as other StringBuilder methods like Append do). I put the replacement char first, and the chars to check at the end. This way, I can leverage the params keyword for easily passing additional strings. However, you don't have to do this if you prefer the other order.

namespace Test.Extensions
{
    public static class StringExtensions
    {
        public static string ReplaceAll(this string str, char replacementCharacter, params char[] chars)
        {
            if (chars.Length == 0)
                return str;

            if (chars.Length == 1)
                return str.Replace(chars[0], replacementCharacter);

            StringBuilder sb = new StringBuilder(str.Length);

            var searcher = new HybridDictionary(chars.Length);
            for (int i = 0; i < chars.Length; i++)
                searcher[chars[i]] = true;

            foreach (var c in str)
            {
                if (searcher.Contains(c))
                    sb.Append(replacementCharacter);
                else
                    sb.Append(c);
            }

            return sb.ToString();
        }

        public static StringBuilder ReplaceAll(this StringBuilder sb, char replacementCharacter, params char[] chars)
        {
            if (chars.Length == 0)
                return sb;

            if (chars.Length == 1)
                return sb.Replace(chars[0], replacementCharacter);

            var searcher = new HybridDictionary(chars.Length);
            for (int i = 0; i < chars.Length; i++)
                searcher[chars[i]] = true;

            for (int i = 0; i < sb.Length; i++)
            {
                var val = sb[i];
                if (searcher.Contains(val))
                    sb[i] = replacementCharacter;
            }

            return sb;
        }
    }
}

其他回答

你也可以简单地写这些字符串扩展方法,并把它们放在你的解决方案中的某个地方:

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

一个. net Core版本,用于将一组已定义的字符串字符替换为特定的字符。它利用了最近引入的Span类型和字符串。创建方法。

其思想是准备一个替换数组,因此不需要对每个字符串字符进行实际的比较操作。因此,替换过程提醒状态机的工作方式。为了避免初始化替换数组的所有项,让我们将oldChar ^ newChar (XOR'ed)值存储在那里,这样做有以下好处:

如果一个字符是不变的:ch ^ ch = 0 -不需要初始化不变的项 最后一个char可以通过XOR'ing: ch ^ repl[ch]: Ch ^ 0 = Ch -不变字符大小写 ch ^ (ch ^ newChar) = newChar -替换的char

因此,唯一的要求是确保替换数组在初始化时为零。我们将使用ArrayPool<char>来避免每次调用ReplaceAll方法时进行分配。并且,为了确保数组为零而不需要调用Array。方法,我们将维护一个专门用于ReplaceAll方法的池。在将替换数组返回到池之前,我们将清除替换数组(仅是精确的项)。

public static class StringExtensions
{
    private static readonly ArrayPool<char> _replacementPool = ArrayPool<char>.Create();

    public static string ReplaceAll(this string str, char newChar, params char[] oldChars)
    {
        // If nothing to do, return the original string.
        if (string.IsNullOrEmpty(str) ||
            oldChars is null ||
            oldChars.Length == 0)
        {
            return str;
        }

        // If only one character needs to be replaced,
        // use the more efficient `string.Replace`.
        if (oldChars.Length == 1)
        {
            return str.Replace(oldChars[0], newChar);
        }

        // Get a replacement array from the pool.
        var replacements = _replacementPool.Rent(char.MaxValue + 1);

        try
        {
            // Intialize the replacement array in the way that
            // all elements represent `oldChar ^ newChar`.
            foreach (var oldCh in oldChars)
            {
                replacements[oldCh] = (char)(newChar ^ oldCh);
            }

            // Create a string with replaced characters.
            return string.Create(str.Length, (str, replacements), (dst, args) =>
            {
                var repl = args.replacements;

                foreach (var ch in args.str)
                {
                    dst[0] = (char)(repl[ch] ^ ch);
                    dst = dst.Slice(1);
                }
            });
        }
        finally
        {
            // Clear the replacement array.
            foreach (var oldCh in oldChars)
            {
                replacements[oldCh] = char.MinValue;
            }

            // Return the replacement array back to the pool.
            _replacementPool.Return(replacements);
        }
    }
}

哦,表演太恐怖了! 答案有点过时了,但仍然……

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();
    }
}

这是最短的方法:

myString = Regex.Replace(myString, @"[;,\t\r ]|[\n]{2}", "\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');