【问题标题】:Use string.Replace to match whole words使用 string.Replace 匹配整个单词
【发布时间】:2012-01-26 04:17:13
【问题描述】:

我正在使用 NET 2.0 和 WinForms。

目前,我需要一个代码来用给定文本中的另一个字符串替换一个字符串,但在文本中它应该只查找整个单词。我的意思是:

string name = @"COUNTER = $40
CLOCK_COUNTER = $60";
name = name.Replace("COUNTER", "COUNT");

它应该只用COUNT 替换COUNTER 的第一个实例,因为那是完整的词。但是,string.Replace 似乎没有考虑到整个单词。

请不要推荐正则表达式。我已经尝试过了,它对我的​​需求来说太慢了。我需要一些非常快速和高效的东西。我怎么能做到这一点?

【问题讨论】:

  • 对不起,这是正则表达式或什么都没有。
  • "请不要推荐正则表达式。"正则表达式变慢但 string.Replace 可以接受的情况到底是什么?您确实了解 string.Replace 是如何发挥作用的,以及它所暗示的内存使用情况对吗?
  • @codesparkle -- CLOCK_COUNTER 后面有一个空格,但还有一个前缀。所以我认为“单词”被定义为“之前的换行符和之后的空格”..
  • @david 我想我的问题是,1 秒的额外执行时间是否值得推出您自己的自定义版本 /\b(word)\b/ 所涉及的额外复杂性?我们需要知道性能问题的背景。你是在一个紧密的循环内部做这个吗?是一次性的批处理文件处理器吗? “足够快”有多快? “慢”有多慢?
  • 请注意,日语和泰语等某些语言不会在单词之间放置空格。

标签: c# string replace .net-2.0


【解决方案1】:
string input = @"COUNTER = $40
CLOCK_COUNTER = $60";

string name = Regex.Replace(input, @"\bCOUNTER\b", "COUNT");

\b 标记单词边界。


正则表达式的唯一替代方法是开发您自己的算法!搜索“COUNTER”并测试前面和后面的字符是否不是单词字符。


编辑

这是我作为扩展方法的解决方案:

public static class ReplaceWordNoRegex
{
    private static bool IsWordChar(char c)
    {
        return Char.IsLetterOrDigit(c) || c == '_';
    }

    public static string ReplaceFullWords(this string s, string oldWord, string newWord)
    {
        if (s == null) {
            return null;
        }
        int startIndex = 0;
        while (true) {
            int position = s.IndexOf(oldWord, startIndex);
            if (position == -1) {
                return s;
            }
            int indexAfter = position + oldWord.Length;
            if ((position == 0 || !IsWordChar(s[position - 1])) && (indexAfter == s.Length || !IsWordChar(s[indexAfter]))) {
                s = s.Substring(0, position) + newWord + s.Substring(indexAfter);
                startIndex = position + newWord.Length;
            } else {
                startIndex = position + oldWord.Length;
            }
        }
    }
}

编辑#2: 这是一个使用 StringBuilder 的解决方案。

public static string ReplaceFullWords(this string s, string oldWord, string newWord)
{
    if (s == null) {
        return null;
    }
    int startIndex = 0; // Where we start to search in s.
    int copyPos = 0; // Where we start to copy from s to sb.
    var sb = new StringBuilder();
    while (true) {
        int position = s.IndexOf(oldWord, startIndex);
        if (position == -1) {
            if (copyPos == 0) {
                return s;
            }
            if (s.Length > copyPos) { // Copy last chunk.
                sb.Append(s.Substring(copyPos, s.Length - copyPos));
            }
            return sb.ToString();
        }
        int indexAfter = position + oldWord.Length;
        if ((position == 0 || !IsWordChar(s[position - 1])) && (indexAfter == s.Length || !IsWordChar(s[indexAfter]))) {
            sb.Append(s.Substring(copyPos, position - copyPos)).Append(newWord);
            copyPos = position + oldWord.Length;
        }
        startIndex = position + oldWord.Length;
    }
}

【讨论】:

  • 虽然这是他应该做的,但这确实与他的要求背道而驰(没有正则表达式)。
  • 因为他不想使用正则表达式的原因是为了速度,并且假设他正在处理数千个字符串和多个替换,您可能应该使用预先分配到长度的字符串生成器在这里输入字符串。如果您要推出自己的算法,那么高效地进行是有意义的。
  • StringBuilder 没有IndexOf(),这意味着您必须在原始字符串上查找位置并在 StringBuilder 上构造新字符串。不是很明显。
  • 不过,我添加了一个 StringBuilder 版本。这有点难理解。
【解决方案2】:

小解决方法:

string name = @"COUNTER = $40
CLOCK_COUNTER = $60";
name=" "+name;
name = name.Replace(" COUNTER ", " COUNT ");

主要思想是你必须用某种符号标记你要替换的单词,而其他你不想替换的单词没有

【讨论】:

  • 建议其他没有正则表达式的东西!
  • 这不能代替 COUNTER 因为它前面没有空格?你的意思是name = " " + name;
  • @elastep “在给定的文本中”。此解决方案特定于给定示例。
【解决方案3】:

我认为你无法比 RegExp 更快地实现字符串替换(我说的是开发时间)

        string input = @"COUNTER = $40 CLOCK_COUNTER = $60";
        string pattern = @"\bCOUNTER\b";
        string replacement = "COUNT";
        var regex = new Regex(pattern,RegexOptions.Compiled);
        string result = regex.Replace(input, replacement);

如果您打算重用,添加 RegexOptions.Compiled 会加快速度

-------更新--------------- --

我记得这篇文章可能适合您的需求:

http://www.codeproject.com/KB/string/fastestcscaseinsstringrep.aspx

【讨论】:

  • 这不是真的,从技术上讲,如果你滚动旧的字符串替换算法,预先分配一个新的字符串生成器到正确的大小,我相信你可以让它更快。关键是它几乎肯定不值得。
  • 是的,我同意。我所说的“更快”意味着开发时间
猜你喜欢
  • 1970-01-01
  • 2012-03-29
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 2012-06-22
  • 2014-08-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多