.net正则表达式搜索和string.replace

时间:2015-12-01 10:10:02

标签: c# regex replace

我的xml文件大约是7mb。我必须从一些节点中删除一些无效字符。有很多节点,如“标题”,“国家”等等..

我为“标题”节点拥有31000个匹配项,并且耗时超过35分钟。这对我的项目要求是不可接受的,我该如何优化这个

方法调用

  fileText = RemoveInvalidCharacters(fileText, "title", @"(&#[xX]?[A-Fa-f\d]+;)|[^\w\s\/\;\&\.@-]", "$1");  

方法定义

private static string RemoveInvalidCharacters(string fileText, string nodeName, string regexPattern, string regexReplacement)
        {
            foreach (Match match in Regex.Matches(fileText, @"<" + nodeName + ">(.*)</" + nodeName + ">"))
            {
                var oldValue = match.Groups[0].Value;
                var newValue = "<" + nodeName + ">" + Regex.Replace(match.Groups[1].Value, regexPattern, regexReplacement) +
                               "</" + nodeName + ">";
                fileText = fileText.Replace(oldValue, newValue);
            }

            return fileText;
        }

1 个答案:

答案 0 :(得分:1)

您可以使用Regex命名空间中的工具来处理解析,而不是使用System.Xml.Linq解析Xml文档,这本身就更快,更容易使用。

这是一个示例程序,它采用一个包含35,000个节点的结构。我保留了你的正则表达式字符串来检查坏字符,但是我已经将它指定为Compiled正则表达式字符串,它应该会更好虽然不可否认,但当我比较两者时,表现并不是一个巨大的增长。 More info

此示例使用Descendants,它引用您在指定元素中的参数中指定的所有元素的引用(在本例中,我们从根元素开始)。这些结果按ContainsBadCharacters方法过滤。

为了简单起见,我没有让foreach循环DRY,但它可能值得这样做。

在我的机器上,运行时间不到一秒钟,但时间会因机器性能和出现不良字符而有所不同。

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        static Regex r = new Regex(@"(&#[xX]?[A-Fa-f\d]+;)|[^\w\s\/\;\&\.@-]", RegexOptions.Compiled);

        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            var xmls = new StringBuilder("<Nodes>");
            for(int i = 0;i<35000;i++)
            {
                xmls.Append(@"<Node>
                                  <Title>Lorem~~~~</Title>
                                  <Country>Ipsum!</Country>
                               </Node>");
            }
            xmls.Append("</Nodes>");

            var doc = XDocument.Parse(xmls.ToString());

            sw.Start();
            foreach(var element in doc.Descendants("Title").Where(ContainsBadCharacters))
            {               
                element.Value = r.Replace(element.Value, "$1");
            }
            foreach (var element in doc.Descendants("Country").Where(ContainsBadCharacters))
            {
                element.Value = r.Replace(element.Value, "$1");
            }
            sw.Stop();

            var saveFile = new FileInfo(Path.Combine(Assembly.GetExecutingAssembly().Location.Substring(0, 
                Assembly.GetExecutingAssembly().Location.LastIndexOf(@"\")), "test.txt"));
            if (!saveFile.Exists) saveFile.Create();

            doc.Save(saveFile.FullName);
            Console.WriteLine(sw.Elapsed);
            Console.Read();
        }

        static bool ContainsBadCharacters(XElement item)
        {
            return r.IsMatch(item.Value);
        }
    }
}