从极长的字符串中删除标点符号

时间:2018-02-11 17:55:56

标签: c# string visual-studio

我正在为我的一门课程编写书籍加密程序而且我遇到了一个问题。我们的教授给了我们一个使用说“傲慢与偏见”作为用来加密的书的例子,所以我选择那个来测试我的程序。我用来从字符串中删除标点符号的当前函数耗时太长,以至于程序被强制进入中断模式。这个函数适用于较小的字符串,甚至页面长,但是当我提供它Pride and Prejudice时,它需要很长时间。

public void removePunctuation(ref string s) {
    string result = "";
    for (int i = 0; i < s.Length; i++) {
        if (Char.IsWhiteSpace(s[i])) {
            result += ' ';
        } else if (!Char.IsLetter(s[i]) && !Char.IsNumber(s[i])) {
            // do nothing
        } else {
            result += s[i];
        }
    }
    s = result;
}

所以我认为如果有人有任何建议,我需要更快的方法从此字符串中删除标点符号?我知道循环每个角色都很可怕,但我很难过,而且我从来没有深入学过正则表达式。

编辑:我被问到如何将字符串存储在字典类中!这是实际使用格式化字符串的另一个类的构造函数。

        public CodeBook(string book)
    {
        BookMap = new Dictionary<string, List<int>>();
        Key = book.Split(null).ToList(); // split string into words
        foreach(string s in Key)
        {
            if (!BookMap.Keys.Contains(s))
            {
                BookMap.Add(s, Enumerable.Range(0, Key.Count).Where(i => Key[i] == s).ToList());
                // add word and add list of occurrances of word
            }
        }
    }

3 个答案:

答案 0 :(得分:3)

这很慢,因为你通过循环中的连接来构造字符串。您有几种方法更高效:

  • 使用StringBuilder - 与每次添加字符时构造新对象的字符串连接不同,此方法通过更大的块扩展正在构建的字符串,从而防止过多的垃圾创建。
  • 使用LINQ的Where 过滤 - 这种方法一次性构建一个char数组,然后构造一个string来自它。
  • 使用正则表达式Replace - 此方法经过优化,可以处理几乎无限大小的字符串。
  • 滚动您自己的算法 - 创建一个与原始字符串长度相对应的char数组。遍历字符串,并将要保留的字符添加到数组中。使用string's constructor that takes the array, the initial index, and the length一次构造字符串。

答案 1 :(得分:1)

循环遍历每个角色一次并不是那么糟糕。你在一次通过中完成所有这一切,这是不容易避免的。

问题在于,无论何时执行类似

的操作,框架都需要分配(部分)字符串的新副本。
result += s[i];

您可以通过引入StringBuilder documented here来附加非标点字符来避免这种情况。

public string removePunctuation(string s) 
{
    var result = new StringBuilder();
    for (int i = 0; i < s.Length; i++) {
        if (Char.IsWhiteSpace(s[i])) {
            result.Append(" ");
        } else if (!Char.IsLetter(s[i]) && !Char.IsNumber(s[i])) {
            // do nothing
        } else {
            result.Append(s[i]);
        }
    }
    return result.ToString();
}

您可以使用改进的算法进一步减少必要的Append调用次数,例如,查看下一个标点符号并一次追加较大的部分,或使用现有的字符串操作库,如RegEx 。但是上面的StringBuilder的引入应该会给你一个显着的性能提升。

  

我从来没有深入学过正则表达式

使用您选择的搜索服务提供商,您最终可能会获得一个可以学习和使用的经过测试的解决方案:https://stackoverflow.com/a/5871826/1132334

答案 2 :(得分:0)

您可以使用正则表达式删除标点符号,如下所示。

public string removePunctuation(string s) 
{
    string result = Regex.Replace(s, @"[^\w\s]", "");
    return result;
}
  

^表示:不是这些字符(字母,数字)   \w表示:字符。
  \s表示:空格字符。