【问题标题】:Remove characters from C# string从 C# 字符串中删除字符
【发布时间】:2022-01-09 13:20:08
【问题描述】:

如何从字符串中删除字符?例如:"My name @is ,Wan.;'; Wan"

我想从该字符串中删除字符'@', ',', '.', ';', '\'',使其变为"My name is Wan Wan"

【问题讨论】:

标签: c# .net


【解决方案1】:
var str = "My name @is ,Wan.;'; Wan";
var charsToRemove = new string[] { "@", ",", ".", ";", "'" };
foreach (var c in charsToRemove)
{
    str = str.Replace(c, string.Empty);
}

但如果您想删除所有非字母字符,我可能会建议另一种方法

var str = "My name @is ,Wan.;'; Wan";
str = new string((from c in str
                  where char.IsWhiteSpace(c) || char.IsLetterOrDigit(c)
                  select c
       ).ToArray());

【讨论】:

  • 也可以这样,str = new string(str.Where(x=>char.IsWhiteSpace(x)||char.IsLetterOrDigit(x)).ToArray());跨度>
  • 我必须查一下,string.Empty 不会为比较创建字符串,因此它比“”更有效。 (stackoverflow.com/questions/151472/…)
  • 我是唯一一个得到“参数 2:无法从 'string' 转换为 'char'” om string.Empty 的人吗?
  • @OddDev 只有在循环遍历的数组是字符列表时才会出现此错误。如果它们是字符串,这应该可以工作
  • 另外,请注意,如果要使用 string.Empty 作为第二个参数,则要使“str.Replace”功能正常工作,第一个参数必须是“字符串”。如果您使用 char(即 'a' )作为第一个参数,您还需要一个 char 作为第二个参数。否则,你会得到上面@OddDev 提到的“Argument 2: cannot convert from 'string' to 'char'”错误
【解决方案2】:

最简单的方法是使用String.Replace:

String s = string.Replace("StringToReplace", "NewString");

【讨论】:

    【解决方案3】:

    简单:

    String.Join("", "My name @is ,Wan.;'; Wan".Split('@', ',' ,'.' ,';', '\''));
    

    【讨论】:

    • 可读性并不令人惊讶,但它似乎是这里性能最高的解决方案。见comment
    【解决方案4】:

    字符串只是一个字符数组,所以使用 Linq 进行替换(类似于上面的 Albin,除了使用 linq contains 语句进行替换):

    var resultString = new string(
            (from ch in "My name @is ,Wan.;'; Wan"
             where ! @"@,.;\'".Contains(ch)
             select ch).ToArray());
    

    第一个字符串是要替换字符的字符串, 第二个是包含字符的简单字符串

    【讨论】:

    • Albin 的 Linq 解决方案可能更好,除非您希望过滤掉额外的字符(未被空格、字母和数字覆盖)。
    【解决方案5】:
     string x = "My name @is ,Wan.;'; Wan";
     string modifiedString = x.Replace("@", "").Replace(",", "").Replace(".", "").Replace(";", "").Replace("'", "");
    

    【讨论】:

    【解决方案6】:

    听起来像是 RegEx 的理想应用程序 - 一种专为快速文本操作而设计的引擎。在这种情况下:

    Regex.Replace("He\"ll,o Wo'r.ld", "[@,\\.\";'\\\\]", string.Empty)
    

    【讨论】:

    • 似乎这比基于迭代器的方法效率更高,尤其是如果您可以使用已编译的正则表达式;
    • 这应该是公认的答案,尤其是因为就像@AdeMiller 所说的那样,它会更有效率。
    • 这并不比循环快,这是一个常见的误解,即正则表达式总是比循环快。正则表达式并不神奇,在它们的核心,它们必须在某些时候遍历字符串来执行它们的操作,并且由于正则表达式本身的开销,它们可能会慢得多。当涉及到需要数十行代码和多个循环的极其复杂的操作时,它们确实表现出色。针对简单的未优化循环测试此正则表达式的编译版本 50000 次,正则表达式慢 6 倍。
    • 内存效率如何?在分配新字符串的意义上,正则表达式不是更有效吗?
    • 也许我在断言 RegEx 速度很快时说错了。除非这是一个非常紧密的循环的中心,否则其他考虑因素,这样的可读性和可维护性可能会超过像这样的小操作的性能。
    【解决方案7】:

    不太具体到您的问题,可以通过在正则表达式中列出可接受的字符来从字符串中删除所有标点符号(空格除外):

    string dirty = "My name @is ,Wan.;'; Wan";
    
    // only space, capital A-Z, lowercase a-z, and digits 0-9 are allowed in the string
    string clean = Regex.Replace(dirty, "[^A-Za-z0-9 ]", "");
    

    请注意,9 之后有一个空格,以免从您的句子中删除空格。第三个参数是一个空字符串,用于替换任何不属于正则表达式的子字符串。

    【讨论】:

      【解决方案8】:

      另一个简单的解决方案:

      var forbiddenChars = @"@,.;'".ToCharArray();
      var dirty = "My name @is ,Wan.;'; Wan";
      var clean = new string(dirty.Where(c => !forbiddenChars.Contains(c)).ToArray());
      

      【讨论】:

        【解决方案9】:

        我不妨把它扔在这里。

        制作一个扩展来从字符串中删除字符:

        public static string RemoveChars(this string input, params char[] chars)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < input.Length; i++)
            {
                if (!chars.Contains(input[i]))
                    sb.Append(input[i]);
            }
            return sb.ToString();
        }
        

        它可以像这样使用:

        string str = "My name @is ,Wan.;'; Wan";
        string cleanedUpString = str.RemoveChars('@', ',', '.', ';', '\'');
        

        或者像这样:

        string str = "My name @is ,Wan.;'; Wan".RemoveChars('@', ',', '.', ';', '\'');
        

        【讨论】:

        • 这是最好的解决方案,因为它使内存分配的数量最少。我还将原始字符串的长度设置为字符串构建器的初始容量,例如: new StringBuilder(input.Length) 用于实现最少数量的内存分配。
        【解决方案10】:

        这里有很多好的答案,这是我的补充以及几个可用于帮助测试正确性的单元测试,我的解决方案类似于上面的@Rianne,但使用 ISet 来提供 O(1) 替换字符的查找时间(也类似于@Albin Sunnanbo 的 Linq 解决方案)。

            using System;
            using System.Collections.Generic;
            using System.Linq;
        
            /// <summary>
            /// Returns a string with the specified characters removed.
            /// </summary>
            /// <param name="source">The string to filter.</param>
            /// <param name="removeCharacters">The characters to remove.</param>
            /// <returns>A new <see cref="System.String"/> with the specified characters removed.</returns>
            public static string Remove(this string source, IEnumerable<char> removeCharacters)
            {
                if (source == null)
                {
                    throw new  ArgumentNullException("source");
                }
        
                if (removeCharacters == null)
                {
                    throw new ArgumentNullException("removeCharacters");
                }
        
                // First see if we were given a collection that supports ISet
                ISet<char> replaceChars = removeCharacters as ISet<char>;
        
                if (replaceChars == null)
                {
                    replaceChars = new HashSet<char>(removeCharacters);
                }
        
                IEnumerable<char> filtered = source.Where(currentChar => !replaceChars.Contains(currentChar));
        
                return new string(filtered.ToArray());
            }
        

        NUnit (2.6+) 测试在这里

        using System;
        using System.Collections;
        using System.Collections.Generic;
        using NUnit.Framework;
        
        [TestFixture]
        public class StringExtensionMethodsTests
        {
            [TestCaseSource(typeof(StringExtensionMethodsTests_Remove_Tests))]
            public void Remove(string targetString, IEnumerable<char> removeCharacters, string expected)
            {
                string actual = StringExtensionMethods.Remove(targetString, removeCharacters);
        
                Assert.That(actual, Is.EqualTo(expected));
            }
        
            [TestCaseSource(typeof(StringExtensionMethodsTests_Remove_ParameterValidation_Tests))]
            public void Remove_ParameterValidation(string targetString, IEnumerable<char> removeCharacters)
            {
                Assert.Throws<ArgumentNullException>(() => StringExtensionMethods.Remove(targetString, removeCharacters));
            }
        }
        
        internal class StringExtensionMethodsTests_Remove_Tests : IEnumerable
        {
            public IEnumerator GetEnumerator()
            {
                yield return new TestCaseData("My name @is ,Wan.;'; Wan", new char[] { '@', ',', '.', ';', '\'' }, "My name is Wan Wan").SetName("StringUsingCharArray");
                yield return new TestCaseData("My name @is ,Wan.;'; Wan", new HashSet<char> { '@', ',', '.', ';', '\'' }, "My name is Wan Wan").SetName("StringUsingISetCollection");
                yield return new TestCaseData(string.Empty, new char[1], string.Empty).SetName("EmptyStringNoReplacementCharactersYieldsEmptyString");
                yield return new TestCaseData(string.Empty, new char[] { 'A', 'B', 'C' }, string.Empty).SetName("EmptyStringReplacementCharsYieldsEmptyString");
                yield return new TestCaseData("No replacement characters", new char[1], "No replacement characters").SetName("StringNoReplacementCharactersYieldsString");
                yield return new TestCaseData("No characters will be replaced", new char[] { 'Z' }, "No characters will be replaced").SetName("StringNonExistantReplacementCharactersYieldsString");
                yield return new TestCaseData("AaBbCc", new char[] { 'a', 'C' }, "ABbc").SetName("CaseSensitivityReplacements");
                yield return new TestCaseData("ABC", new char[] { 'A', 'B', 'C' }, string.Empty).SetName("AllCharactersRemoved");
                yield return new TestCaseData("AABBBBBBCC", new char[] { 'A', 'B', 'C' }, string.Empty).SetName("AllCharactersRemovedMultiple");
                yield return new TestCaseData("Test That They Didn't Attempt To Use .Except() which returns distinct characters", new char[] { '(', ')' }, "Test That They Didn't Attempt To Use .Except which returns distinct characters").SetName("ValidateTheStringIsNotJustDistinctCharacters");
            }
        }
        
        internal class StringExtensionMethodsTests_Remove_ParameterValidation_Tests : IEnumerable
        {
            public IEnumerator GetEnumerator()
            {
                yield return new TestCaseData(null, null);
                yield return new TestCaseData("valid string", null);
                yield return new TestCaseData(null, new char[1]);
            }
        }
        

        【讨论】:

          【解决方案11】:
          new List<string> { "@", ",", ".", ";", "'" }.ForEach(m => str = str.Replace(m, ""));
          

          【讨论】:

            【解决方案12】:

            原地复制/踩踏:

              private static string RemoveDirtyCharsFromString(string in_string)
                 {
                    int index = 0;
                    int removed = 0;
            
                    byte[] in_array = Encoding.UTF8.GetBytes(in_string);
            
                    foreach (byte element in in_array)
                    {
                       if ((element == ' ') ||
                           (element == '-') ||
                           (element == ':'))
                       {
                          removed++;
                       }
                       else
                       {
                          in_array[index] = element;
                          index++;
                       }
                    }
            
                    Array.Resize<byte>(ref in_array, (in_array.Length - removed));
                    return(System.Text.Encoding.UTF8.GetString(in_array, 0, in_array.Length));
                 }
            

            不确定效率 w.r.t.其他方法(即在 C# 执行中作为副作用发生的所有函数调用和实例化的开销)。

            【讨论】:

              【解决方案13】:

              看来最快捷的办法是把LINQ和string.Concat结合起来:

              var input = @"My name @is ,Wan.;'; Wan";
              var chrs = new[] {'@', ',', '.', ';', '\''};
              var result = string.Concat(input.Where(c => !chrs.Contains(c)));
              // => result = "My name is Wan Wan" 
              

              请参阅C# demo。请注意,string.Concatstring.Join("", ...) 的快捷方式。

              请注意,使用正则表达式删除单个已知字符仍然可以动态构建,尽管人们认为正则表达式较慢。但是,这里有一种构建动态正则表达式的方法(您只需要一个字符类):

              var pattern = $"[{Regex.Escape(new string(chrs))}]+";
              var result = Regex.Replace(input, pattern, string.Empty);
              

              another C# demo。正则表达式看起来像[@,\.;']+(匹配一个或多个(+)连续出现的@,.;' 字符),其中的点不必是已转义,但 Regex.Escape 将是转义必须转义的其他字符所必需的,例如 \^]-,它们在您无法预测的字符类中的位置。

              【讨论】:

              【解决方案14】:

              我用扩展方法和字符串数组,我认为string[]char[]更有用,因为char也可以是字符串:

              public static class Helper
              {
                  public static string RemoverStrs(this string str, string[] removeStrs)
                  {
                      foreach (var removeStr in removeStrs)
                          str = str.Replace(removeStr, "");
                      return str;
                  }
              }
              

              那么你可以在任何地方使用它:

              string myname = "My name @is ,Wan.;'; Wan";
              string result = myname.RemoveStrs(new[]{ "@", ",", ".", ";", "\\"});
              

              【讨论】:

                【解决方案15】:

                比较各种建议(以及在单个字符替换的上下文中与目标的各种大小和位置进行比较)。

                在这种特殊情况下,分割目标并加入替换(在本例中为空字符串)是最快的,至少是 3 倍。最终,性能会根据替换的数量而有所不同,其中替换在源中,以及源的大小。 #ymmv

                结果

                (完整结果here

                | Test                      | Compare | Elapsed                                                            |
                |---------------------------|---------|--------------------------------------------------------------------|
                | SplitJoin                 | 1.00x   | 29023 ticks elapsed (2.9023 ms) [in 10K reps, 0.00029023 ms per]   |
                | Replace                   | 2.77x   | 80295 ticks elapsed (8.0295 ms) [in 10K reps, 0.00080295 ms per]   |
                | RegexCompiled             | 5.27x   | 152869 ticks elapsed (15.2869 ms) [in 10K reps, 0.00152869 ms per] |
                | LinqSplit                 | 5.43x   | 157580 ticks elapsed (15.758 ms) [in 10K reps, 0.0015758 ms per]   |
                | Regex, Uncompiled         | 5.85x   | 169667 ticks elapsed (16.9667 ms) [in 10K reps, 0.00169667 ms per] |
                | Regex                     | 6.81x   | 197551 ticks elapsed (19.7551 ms) [in 10K reps, 0.00197551 ms per] |
                | RegexCompiled Insensitive | 7.33x   | 212789 ticks elapsed (21.2789 ms) [in 10K reps, 0.00212789 ms per] |
                | Regex Insensitive         | 7.52x   | 218164 ticks elapsed (21.8164 ms) [in 10K reps, 0.00218164 ms per] |
                

                测试工具(LinqPad)

                (注意:PerfVstiming extensions I wrote

                void test(string title, string sample, string target, string replacement) {
                    var targets = target.ToCharArray();
                    
                    var tox = "[" + target + "]";
                    var x = new Regex(tox);
                    var xc = new Regex(tox, RegexOptions.Compiled);
                    var xci = new Regex(tox, RegexOptions.Compiled | RegexOptions.IgnoreCase);
                
                    // no, don't dump the results
                    var p = new Perf/*<string>*/();
                        p.Add(string.Join(" ", title, "Replace"), n => targets.Aggregate(sample, (res, curr) => res.Replace(new string(curr, 1), replacement)));
                        p.Add(string.Join(" ", title, "SplitJoin"), n => String.Join(replacement, sample.Split(targets)));
                        p.Add(string.Join(" ", title, "LinqSplit"), n => String.Concat(sample.Select(c => targets.Contains(c) ? replacement : new string(c, 1))));
                        p.Add(string.Join(" ", title, "Regex"), n => Regex.Replace(sample, tox, replacement));
                        p.Add(string.Join(" ", title, "Regex Insentive"), n => Regex.Replace(sample, tox, replacement, RegexOptions.IgnoreCase));
                        p.Add(string.Join(" ", title, "Regex, Uncompiled"), n => x.Replace(sample, replacement));
                        p.Add(string.Join(" ", title, "RegexCompiled"), n => xc.Replace(sample, replacement));
                        p.Add(string.Join(" ", title, "RegexCompiled Insensitive"), n => xci.Replace(sample, replacement));
                    
                    var trunc = 40;
                    var header = sample.Length > trunc ? sample.Substring(0, trunc) + "..." : sample;
                    
                    p.Vs(header);
                }
                
                void Main()
                {
                    // also see https://stackoverflow.com/questions/7411438/remove-characters-from-c-sharp-string
                    
                    "Control".Perf(n => { var s = "*"; });
                    
                        
                    var text = "My name @is ,Wan.;'; Wan";
                    var clean = new[] { '@', ',', '.', ';', '\'' };
                    
                    test("stackoverflow", text, string.Concat(clean), string.Empty);
                
                    
                    var target = "o";
                    var f = "x";
                    var replacement = "1";
                    
                    var fillers = new Dictionary<string, string> {
                        { "short", new String(f[0], 10) },
                        { "med", new String(f[0], 300) },
                        { "long", new String(f[0], 1000) },
                        { "huge", new String(f[0], 10000) }
                    };
                    
                    var formats = new Dictionary<string, string> {
                        { "start", "{0}{1}{1}" },
                        { "middle", "{1}{0}{1}" },
                        { "end", "{1}{1}{0}" }
                    };
                
                    foreach(var filler in fillers)
                    foreach(var format in formats) {
                        var title = string.Join("-", filler.Key, format.Key);
                        var sample = string.Format(format.Value, target, filler.Value);
                        
                        test(title, sample, target, replacement);
                    }
                }
                

                【讨论】:

                • 终于有一些数字了!干得好@drzaus!
                【解决方案16】:

                我需要从 XML 文件中删除特殊字符。这就是我的做法。 char.ToString() 是这段代码的主角。

                string item = "<item type="line" />"
                char DC4 = (char)0x14;
                string fixed = item.Replace(DC4.ToString(), string.Empty);
                

                【讨论】:

                  【解决方案17】:
                  new[] { ',', '.', ';', '\'', '@' }
                  .Aggregate("My name @is ,Wan.;'; Wan", (s, c) => s.Replace(c.ToString(), string.Empty)); 
                  

                  【讨论】:

                    【解决方案18】:

                    这是我编写的一个方法,它采用了稍微不同的方法。我没有指定要删除的字符,而是告诉我的方法要保留哪些字符——它将删除所有其他字符。

                    在 OP 的示例中,他只想保留字母字符和空格。以下是对我的方法的调用 (C# demo):

                    var str = "My name @is ,Wan.;'; Wan";
                    
                    // "My name is Wan Wan"
                    var result = RemoveExcept(str, alphas: true, spaces: true);
                    

                    这是我的方法:

                    /// <summary>
                    /// Returns a copy of the original string containing only the set of whitelisted characters.
                    /// </summary>
                    /// <param name="value">The string that will be copied and scrubbed.</param>
                    /// <param name="alphas">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
                    /// <param name="numerics">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
                    /// <param name="dashes">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
                    /// <param name="underlines">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
                    /// <param name="spaces">If true, all alphabetical characters (a-zA-Z) will be preserved; otherwise, they will be removed.</param>
                    /// <param name="periods">If true, all decimal characters (".") will be preserved; otherwise, they will be removed.</param>
                    public static string RemoveExcept(string value, bool alphas = false, bool numerics = false, bool dashes = false, bool underlines = false, bool spaces = false, bool periods = false) {
                        if (string.IsNullOrWhiteSpace(value)) return value;
                        if (new[] { alphas, numerics, dashes, underlines, spaces, periods }.All(x => x == false)) return value;
                    
                        var whitelistChars = new HashSet<char>(string.Concat(
                            alphas ? "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" : "",
                            numerics ? "0123456789" : "",
                            dashes ? "-" : "",
                            underlines ? "_" : "",
                            periods ? "." : "",
                            spaces ? " " : ""
                        ).ToCharArray());
                    
                        var scrubbedValue = value.Aggregate(new StringBuilder(), (sb, @char) => {
                            if (whitelistChars.Contains(@char)) sb.Append(@char);
                            return sb;
                        }).ToString();
                    
                        return scrubbedValue;
                    }
                    

                    【讨论】:

                    • 很棒的答案!
                    • 非常好!数字字符串有两次 0。
                    • @JohnKurtz 不错——现在没了。
                    • 这似乎是一种搞乱包含特殊字符或变音符号的文本的好方法......
                    【解决方案19】:

                    这是我通常在相同情况下使用的强大方法:

                    private string Normalize(string text)
                    {
                            return string.Join("",
                                from ch in text
                                where char.IsLetterOrDigit(ch) || char.IsWhiteSpace(ch)
                                select ch);
                    }
                    

                    享受...

                    【讨论】:

                      【解决方案20】:

                      从@drzaus 获取性能数据,这是一种使用最快算法的扩展方法。

                      public static class StringEx
                      {
                          public static string RemoveCharacters(this string s, params char[] unwantedCharacters) 
                              => s == null ? null : string.Join(string.Empty, s.Split(unwantedCharacters));
                      }
                      

                      用法

                      var name = "edward woodward!";
                      var removeDs = name.RemoveCharacters('d', '!');
                      Assert.Equal("ewar woowar", removeDs); // old joke
                      

                      【讨论】:

                        【解决方案21】:

                        这是删除文件名中无效字符的好方法:

                        string.Join(string.Empty, filename.Split(System.IO.Path.GetInvalidFileNameChars()));
                        

                        【讨论】:

                          【解决方案22】:

                          如果要删除所有空格和特殊字符

                                  var input = Console.ReadLine();
                                  foreach (var item in input)
                                  {
                                      var limit = ((int)item);
                          
                                      if (limit>=65 && limit<=90 || limit>=97 && limit<= 122)
                                      {
                                          Console.Write(item);
                                      }
                                      
                                  }
                          

                          【讨论】:

                            猜你喜欢
                            • 2011-12-10
                            • 1970-01-01
                            • 1970-01-01
                            • 2010-12-02
                            • 2015-01-13
                            • 2012-06-25
                            • 2019-11-09
                            相关资源
                            最近更新 更多