C# StringBuilder中的正则表达式替换

C# StringBuilder中的正则表达式替换,c#,regex,stringbuilder,C#,Regex,Stringbuilder,我正在将文本文件的内容写入StringBuilder,然后我想使用正则表达式对StringBuilder中包含的文本执行一些查找/替换操作 我遇到了一个问题,因为StringBuilder replace函数无法接受正则表达式参数 我可以在普通字符串上使用Regex.Replace,但我觉得这样做效率很低,因为.net字符串是不可变的,所以需要在内存中创建两个字符串副本 一旦我更新了文本,我计划将其写回原始文件 解决我的问题的最好和最有效的方法是什么 编辑 除了下面的答案外,我还发现了以下问题,

我正在将文本文件的内容写入StringBuilder,然后我想使用正则表达式对StringBuilder中包含的文本执行一些查找/替换操作

我遇到了一个问题,因为StringBuilder replace函数无法接受正则表达式参数

我可以在普通字符串上使用Regex.Replace,但我觉得这样做效率很低,因为.net字符串是不可变的,所以需要在内存中创建两个字符串副本

一旦我更新了文本,我计划将其写回原始文件

解决我的问题的最好和最有效的方法是什么

编辑

除了下面的答案外,我还发现了以下问题,这些问题也对我的问题有所帮助-


对于您的时间来说,最好和最有效的解决方案是首先尝试最简单的方法:忘记
StringBuilder
,只使用
Regex.Replace
。然后看看它有多慢——它可能已经足够好了。不要忘记在编译和非编译模式下都尝试正则表达式


如果这不够快,请考虑使用<代码> StringBuilder <代码>,您可以简单地表示任何替换,然后使用<代码>正则表达式。您可能还需要考虑尝试合并替换,减少使用的正则表达式(以及中间字符串)的数量。

< P>我不确定这是否有助于您的场景,但我使用ReGEX遇到了一些内存消耗上限,我需要一个简单的通配符替换扩展方法来在StrugBu建器上推过它。如果您需要复杂的正则表达式匹配和/或反向引用,这是不行的,但是如果简单*或?通配符替换(带有文字“替换”文本)将为您完成任务,那么我问题末尾的解决方法至少会给您带来提升:


这里有一个扩展方法,您可以使用它来实现您想要的功能。它接受一个
字典
,其中键是您要查找的模式,值是您要替换的模式。您仍然可以创建传入字符串的副本,但只需处理一次,而不必为对
Regex.Replace的多个调用创建副本

public static StringBuilder BulkReplace(this StringBuilder source, IDictionary<string, string> replacementMap)
{
    if (source.Length == 0 || replacementMap.Count == 0)
    {
        return source;
    }
    string replaced = Regex.Replace(source.ToString(), String.Join("|", replacementMap.Keys.Select(Regex.Escape).ToArray()), m => replacementMap[m.Value], RegexOptions.IgnoreCase);
    return source.Clear().Append(replaced);
}
公共静态StringBuilder BulkReplace(此StringBuilder源代码,IDictionary replacementMap)
{
if(source.Length==0 | | replacementMap.Count==0)
{
返回源;
}
string replaced=Regex.Replace(source.ToString(),string.Join(“|”),replacementMap.Keys.Select(Regex.Escape.ToArray()),m=>replacementMap[m.Value],RegexOptions.IgnoreCase);
返回source.Clear().Append(已替换);
}
您有3个选项:

  • 像其他人在这里推荐的那样,使用字符串以低效的方式执行此操作

  • Regex
    对象使用
    .Matches()
    调用,并模拟
    .Replace()
    的工作方式(请参见#3)

  • 调整
    Regex
    的Mono实现,以构建接受
    StringBuilder
    Regex
    。几乎所有的工作都已经在Mono中为您完成了,但是将使其工作的部分放到自己的库中需要时间。Mono的
    Regex
    利用了Novell 2002年的JVM实现
    Regex
    ,这一点很奇怪

  • 扩展上述内容:

    2.模拟替换() 通过调用
    .Matches()
    ,跟踪原始字符串中的位置并循环,可以模拟
    LTRReplace
    的行为:

    var matches = regex.Matches(original);
    var sb = new StringBuilder(original.Length);
    int pos = 0; // position in original string
    foreach(var match in matches)
    {
        // Append the portion of the original we skipped
        sb.Append(original.Substring(pos, match.Index));
        pos = match.Index;
    
        // Make any operations you like on the match result, like your own custom Replace, or even run another Regex
    
        pos += match.Value.Length;
    }
    sb.Append(original.Substring(pos, original.Length - 1));
    
    但是,这只会节省一些字符串-Mono方法是唯一真正彻底消除字符串的方法

    3.单声道 这个答案自2014年以来一直被搁置,我从未在评论或搜索中看到基于StringBuilder的Regex land。因此,为了让事情顺利进行,我从Mono中提取了Regex impl,并将其放在这里:

    然后,我创建了一个接口
    IString
    ,以允许输入和输出以更松散的方式传递-使用
    string
    StringBuilder
    char[]
    将每个接口包装在一个实现IString的类中

    结果并不快——微软高度优化的代码运行速度比这段代码快约6倍。但是,我没有对其进行任何优化,特别是在消除底层代码中更深层次的字符串方面(在某些情况下,它强制转换为字符串以运行.ToLower(),但返回到char数组)

    欢迎捐款。下面将讨论2014年以来Mono中的代码工作原理(在从Mono中删除之前不久,用于Microsoft基于字符串的实现):

    使用以的形式实例化IMachineFactory,这毫不奇怪地使
    IMachine
    s成为s。让它们发射是你需要做的大部分事情,尽管如果你只是想了解它是如何为提高效率而构建的,值得注意的是,你要寻找的大部分是在它的基类中


    特别是在
    BaseMachine
    中,是基于
    StringBuilder
    的东西。在该方法中,它首先用初始字符串实例化一个StringBuilder,从那时起,一切都是基于StringBuilder的。如果我们假设内部的Microsoft.Net实现是类似的,那么Regex没有挂起StringBuilder方法实际上是非常令人恼火的。

    我很惊讶我没有想到这一点:实际运行它并查看,而不是猜测速度会是多少。我已经相应地删除了我的推测性答案。如果Regex.Replace足够快,我是否应该考虑内存管理?我是否因为担心创建多个字符串的记忆问题而过度分析/优化了事情?这与其说是一个答案,不如说是一个建议。问题是如何使正则表达式与stringbuilder一起工作,以及答案