2015-12-01 3 views
0

Мой XML-файл составляет около 7 Мб. Мне нужно удалить некоторые недопустимые символы из некоторых узлов. существует множество узлов, таких как «title», «country» и т. д..net Regex Search и string.replace

У меня есть 31000 совпадений для узла «title» и занимает более 35 минут. которые не приемлемы для моих требований к проекту, как можно оптимизировать этот метод

вызов

fileText = RemoveInvalidCharacters(fileText, "title", @"(&#[xX]?[A-Fa-f\d]+;)|[^\w\s\/\;\&\[email protected]]", "$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; 
     } 
+0

Вы CRE вызова 'RemoveSpecialCharacters' но имя метода' RemoveInvalidCharacters' –

+2

Вы можете оптимизировать это, * не используется регулярное выражение для XML разбора *. Используйте правильные инструменты, .NET имеет XML-парсеры и даже низкоуровневые читатели/писатели XML, если полноразмерные парсеры не достаточно быстры. * (Я должен удержаться от соблазна переустановить это на [this] (http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags)) *. –

+0

Я думаю, что проблема может быть с '(. *)' Subpattern. Что делать, если вы используете 'Regex.Matches (fileText, @" <"+ nodeName + @"> ([^ <] * (?: <(?!) [^ <] *) *) ")'? –

ответ

1

Вместо того, чтобы использовать Regex для разбора XML-документа, вы можете использовать инструменты в пространстве имен System.Xml.Linq, чтобы обработать синтаксический анализ для вас, который по своей сути намного быстрее и проще в использовании.

Вот пример программы, которая принимает структуру с 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\/\;\&\[email protected]]", 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); 
     } 
    } 
}