替换C#字符串中的多个字符


178

有替代字符串的更好方法吗?

令我惊讶的是,Replace不包含字符数组或字符串数​​组。我想我可以编写自己的扩展名,但我很好奇是否有更好的内置方法可以执行以下操作?请注意,最后一个Replace是字符串而不是字符。

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

Answers:


205

您可以使用替换正则表达式。

s/[;,\t\r ]|[\n]{2}/\n/g
  • s/ 开头意味着搜索
  • 之间的字符[]是搜索(以任何顺序)的字符
  • 第二个/分隔搜索文本和替换文本

用英语写成:

“搜索;,\t\r(空间)或正好两个连续,\n然后将其替换为\n

在C#中,您可以执行以下操作:(导入后System.Text.RegularExpressions

Regex pattern = new Regex("[;,\t\r ]|[\n]{2}");
pattern.Replace(myString, "\n");

2
\t并且\r包含在中\s。因此,您的正则表达式等效于[;,\s]
NullUserException 2011年

3
\s实际上相当于[ \f\n\r\t\v]所以你包括一些东西存在,这不是在原来的问题。另外,原始问题会询问Replace("\n\n", "\n")您的正则表达式无法处理的问题。
NullUserException 2011年

11
请考虑一下,对于用户无法配置的简单替换操作,使用正则表达式并不是最佳选择,因为与常规字符串操作相比,使用正则表达式非常慢,根据我在搜索“ c#regex性能替换”时发现的第一篇基准文章,它约为13时间慢了。

正则表达式,力量的象形文字!我在这里看到的唯一问题是正则表达式的可读性。许多人拒绝理解它们。我最近在下面添加了一个解决方案,供那些寻找不太复杂的替代方案的人使用。
sɐunıɔןɐqɐp

那么,如果我们想用多个字符替换多个字符,我们该怎么写呢?
哈比普·奥格兹(HabipOğuz),

113

如果您感觉特别聪明并且不想使用正则表达式:

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");

内存效率非常低,尤其是对于较大的字符串。
MarcinJuraszek '18年

@MarcinJuraszek大声笑...这可能是我第一次听说有人声称内置字符串方法比正则表达式的内存效率低。
Paul Walls

10
你是对的。在发布之前,我应该已经进行了测量。我运行基准测试,Regex.Replacestring.Replace连续多次通话慢8倍以上。并且比Split+ 慢4倍Join。参见gist.github.com/MarcinJuraszek/c1437d925548561ba210a1c6ed144452
MarcinJuraszek

1
不错的解决方案!只是一个小插件。不幸的是,如果您也希望替换第一个字符,则此操作将无效。假设您要替换示例字符串中的“ t”字符。Split方法将删除第一个单词“ this”的“ t”,因为它是EmptyEntry。如果使用StringSplitOptions.None而不是RemoveEmptyEntries,则Split将保留该条目,而Join方法将添加分隔符。希望这会有所帮助
Pierre

57

您可以使用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');

20

这是最短的方法:

myString = Regex.Replace(myString, @"[;,\t\r ]|[\n]{2}", "\n");

1
当您需要在初始化器中使用时,此衬板也有帮助。
Guney Ozsan '18年

7

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

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

5

字符串只是不可变的char数组

您只需要使其可变即可:

  • 通过使用 StringBuilder
  • 进入unsafe世界并与指针一起玩(虽然很危险)

并尝试迭代字符数组最少的时间。请注意HashSet此处,因为它避免遍历循环内的字符序列。如果您需要更快的查找,则可以用(基于)HashSet的优化查找来代替。chararray[256]

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

请记住,字符串wchar_t在.net中,您只替换了所有可能字符的子集(并且您将需要65536个布尔变量来优化它……)
gog

2

您也可以简单地编写这些字符串扩展方法,然后将它们放在解决方案中的某个位置:

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



0

Performance-Wise这可能不是最佳解决方案,但它可以工作。

var str = "filename:with&bad$separators.txt";
char[] charArray = new char[] { '#', '%', '&', '{', '}', '\\', '<', '>', '*', '?', '/', ' ', '$', '!', '\'', '"', ':', '@' };
foreach (var singleChar in charArray)
{
   str = str.Replace(singleChar, '_');
}

0
string ToBeReplaceCharacters = @"~()@#$%&amp;+,'&quot;&lt;&gt;|;\/*?";
string fileName = "filename;with<bad:separators?";

foreach (var RepChar in ToBeReplaceCharacters)
{
    fileName = fileName.Replace(RepChar.ToString(), "");
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.