【问题标题】:How can i remove none alphabet chars from a string[]? [duplicate]如何从字符串 [] 中删除无字母字符? [复制]
【发布时间】:2013-07-01 17:09:21
【问题描述】:

这是代码:

StringBuilder sb = new StringBuilder();
Regex rgx = new Regex("[^a-zA-Z0-9 -]");

var words = Regex.Split(textBox1.Text, @"(?=(?<=[^\s])\s+\w)");
for (int i = 0; i < words.Length; i++)
{
    words[i] = rgx.Replace(words[i], "");
}

当我在做Regex.Split() 时,单词还包含带有字符的字符串,例如:

Daniel&gt;

Hello:

\r\nNew

hello---------------------------

我只需要得到没有所有符号的单词

所以我尝试使用这个循环,但我总结说有很多地方有"" 而有些地方只有------------------------

我不能在后面的代码中将其用作字符串。

【问题讨论】:

  • 您可以使用正则表达式执行此操作,例如 (\w+|\s+)。这将为您提供所有单词(无数字)之间有一个或多个空格。
  • @Cort3z \w 为您提供字母、数字和下划线(或更多用于 Unicode)。如果你只想要字母,你可能想要[a-zA-Z]
  • @JoeEnos 没错,完全忘记了。
  • @Cort3z 是的,我几天前也做过同样的事情。

标签: c# regex


【解决方案1】:

为了帮助 Konrad 和 keyboardP 解决他们之间的差异,我使用他们的代码进行了基准测试。事实证明,keyboardP 的代码比 Konrad 的代码快 10 倍

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string input = "asdf234!@#*advfk234098awfdasdfq9823fna943";
                DateTime start = DateTime.Now;
                for (int i = 0; i < 100000; i++)
                {
                    RemoveNonUnicodeLetters(input);
                }
                Console.WriteLine(DateTime.Now.Subtract(start).TotalSeconds);
                start = DateTime.Now;
                for (int i = 0; i < 100000; i++)
                {
                    RemoveNonUnicodeLetters2(input);
                }
                Console.WriteLine(DateTime.Now.Subtract(start).TotalSeconds);
            }
            public static string RemoveNonUnicodeLetters(string input)
            {
                StringBuilder sb = new StringBuilder();
                foreach (char c in input)
                {
                    if (Char.IsLetter(c))
                        sb.Append(c);
                }

                return sb.ToString();
            }
            public static string RemoveNonUnicodeLetters2(string input)
            {
                var result = Regex.Replace(input, "\\P{L}", "");
                return result;
            }
        }
    }

我明白了

0.12
1.2

作为输出

更新:

为了查看是否是正则表达式编译减慢了正则表达式方法,我将正则表达式放在一个只构造一次的静态变量中。

            static Regex rex = new Regex("\\P{L}");
            public static string RemoveNonUnicodeLetters2(string input)
            {
                var result = rex.Replace(input,m => "");
                return result;
            }

但这对运行时没有影响。

【讨论】:

  • 感谢基准测试。我只是用更少的循环和更长的字符串输入添加了我的,结果是相关的。
  • 只是为了好玩,如果你对char[]而不是StringBuilder进行基准测试,你会得到大约10%的更好结果。 (构建一个字符串大小的临时数组,遍历字符串,用匹配项填充临时数组,然后将临时数组复制到正确大小的新数组中,并将其传递给string 构造函数)。
  • 对于更复杂的正则表达式,提取创建实际上对运行时有很大影响。我仍然对 .NET 的正则表达式实现感到非常失望。正则表达式应该非常快。 FWIW,您的基准代码不是很可靠,您应该使用StopWatch,您可能应该使用更多的迭代(尽管在这种情况下可能很好)并且您应该交错测试调用以减轻后台进程的周期性影响这可能会使结果产生偏差。理想情况下,您还可以绘制分布图,以确保没有异常值会导致均值出现偏差。
  • StopWatch 只有在您查看的时间快于 15 毫秒时才会更准确。 DateTime.Now 适用于 15 毫秒。我跑的时间比那长了 100 倍。 10 万次迭代就足够了。我只是将它提高到大约 1 秒的运行时间——那是数十亿个 CPU 周期。我以相同的结果运行了两次代码,然后发布了结果。
  • @Joe Enos,如果您使用字符串的大小(new StringBuilder(string.Length))预先分配 StringBuilder,您可能会获得类似的 10% 加速,因为 StringBuilder 分配了 16 个字节,然后是 32,然后是 64,因为它正在运行。这是我几乎从未在网上看到的对 StringBuilder 的极大加速。
【解决方案2】:

您不需要正则表达式来清除非字母。这将删除所有非 unicode 字母。

public string RemoveNonUnicodeLetters(string input)
{
    StringBuilder sb = new StringBuilder();
    foreach(char c in input)
    {
        if(Char.IsLetter(c))
           sb.Append(c);
    }

    return sb.ToString();
}

或者,如果你只想允许拉丁字母,你可以使用这个

public string RemoveNonLatinLetters(string input)
{
    StringBuilder sb = new StringBuilder();
    foreach(char c in input)
    {
        if(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
           sb.Append(c);
    }

    return sb.ToString();
}

基准与正则表达式

public static string RemoveNonUnicodeLetters(string input)
{
       StringBuilder sb = new StringBuilder();
       foreach (char c in input)
       {
            if (Char.IsLetter(c))
                sb.Append(c);
       }

            return sb.ToString();
}



static readonly Regex nonUnicodeRx = new Regex("\\P{L}");

public static string RemoveNonUnicodeLetters2(string input)
{
     return nonUnicodeRx.Replace(input, "");
}


static void Main(string[] args)
{

    Stopwatch sw = new Stopwatch();

    StringBuilder sb = new StringBuilder();


    //generate guids as input
    for (int j = 0; j < 1000; j++)
    {
        sb.Append(Guid.NewGuid().ToString());
    }

    string input = sb.ToString();

    sw.Start();

    for (int i = 0; i < 1000; i++)
    {
        RemoveNonUnicodeLetters(input);
    }

    sw.Stop();
    Console.WriteLine("SM: " + sw.ElapsedMilliseconds);

    sw.Restart();
    for (int i = 0; i < 1000; i++)
    {
        RemoveNonUnicodeLetters2(input);
    }

    sw.Stop();
    Console.WriteLine("RX: " + sw.ElapsedMilliseconds);


}

输出(SM = 字符串操作,RX = 正则表达式)

SM: 581
RX: 9882

SM: 545
RX: 9557

SM: 664
RX: 10196

【讨论】:

  • ... 比清晰直接表达意图的正则表达式更容易维护?这听起来很可笑。这就是正则表达式而生的那种东西。
  • 我敢打赌,在描述方面,人们会更喜欢方法名称而不是正则表达式。正则表达式,恕我直言,适用于字符串解析过于复杂或冗长的情况。
  • 所以把正则表达式放在一个方法中。
  • 公平评论。也许我是少数,但当要求是基本的时,我会尝试选择字符串操作。此代码不是多次输入,而是一次输入并重复使用。
  • 我和你在一起。正则表达式很棒,但清晰的代码更好。
【解决方案3】:

keyboardP 的解决方案不错——考虑一下。但正如我在 cmets 中所说的那样,正则表达式实际上是完成这项工作的正确工具,你只是让它变得不必要地复杂。实际的解决方案是单行:

var result = Regex.Replace(input, "\\P{L}", "");

\P{…} specifies a Unicode character class we do not want to match(与\p{…}相反)。 Lletters 的 Unicode 字符类。

当然,将它封装到一个方法中是有意义的,就像keyboardP 所做的那样。为了避免重新编译正则表达式,您还应该考虑将正则表达式的创建从实际代码中提取出来(尽管这可能不会对性能产生很大影响):

static readonly Regex nonUnicodeRx = new Regex("\\P{L}");

public static string RemoveNonUnicodeLetters(string input) {
    return nonUnicodeRx.Replace(input, "");
}

【讨论】:

  • 我的一两个同事可能了解"\\P{L}"。我有大约 35 位同事。我必须承认,该公司不雇用顶尖人才,但您可能理解这对可维护性有什么影响。我经常使用正则表达式(尤其是开发过程中),但在重要代码中可以很容易地避免使用正则表达式时就不...
  • @owlstead 所以在它旁边放一条评论。这不是为工作使用正确工具的正当理由。相反,你学习工具——或者,在你的情况下,教育同事。是的,正则表达式对于外行来说是神秘的,但条件运算符也是如此,但是有一个压倒性的共识是你应该使用这样的习语。我什至不确定评论是否适合这里——代码完全是不言自明的……鉴于存在适当的正则表达式文档。
  • 哇,这是一个很棒的解决方案
猜你喜欢
  • 2018-12-02
  • 1970-01-01
  • 2014-01-26
  • 2017-03-11
  • 1970-01-01
  • 2020-03-20
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多