2014-01-30 5 views
1

Ниже приведен метод, который я написал для чтения из текстового файла. Во время чтения мне нужно сопоставить строку строки с заданным регулярным выражением, и если она соответствует, мне нужно добавить строку в коллекцию.Чтение из текстового файла с помощью Regex

private static void GetOrigionalRGBColours(string txtFile) 
{ 
    string tempLineValue; 
    Regex regex = new Regex(@"^\d+.?\d* \d+.?\d* \d+.?\d* SRGB$"); 

    using (StreamReader inputReader = new StreamReader(txtFile)) 
    { 
     while (null != (tempLineValue = inputReader.ReadLine()))      
     { 
      if (regex.Match(tempLineValue).Success 
       && tempLineValue != "1 1 1 SRGB" 
       && tempLineValue != "0 0 0 SRGB") 
      { 
       string[] rgbArray = tempLineValue.Split(' '); 
       RGBColour rgbColour = new RGBColour() { Red = Convert.ToDecimal(rgbArray[0]), Green = Convert.ToDecimal(rgbArray[1]), Blue = Convert.ToDecimal(rgbArray[2]) }; 
       originalColourList.Add(rgbColour); 
      } 
     } 
    } 
} 

Когда этот метод выполняется для текстового файла 4MB, имеющие 28653 строк, она занимает около 3 минут просто закончить вышеупомянутый метод. Кроме того, в результате вышеуказанного запуска originalColourList заселен 582 пунктами.

Может ли кто-нибудь указать, как я могу улучшить производительность этого метода? Фактический размер текстового файла может увеличиться до 60MB.

FYI-
Right Match для Regex: 0,922 0,833 0,855 SRGB
Неправильный матч для Regex:/SRGB/setrgbcolor нагрузки Защиту
Файл TXT изначально файл постскриптум, я сэкономил, что в текстовый файл для манипуляций используя C#.

+0

Вы можете получить более качественные ответы, если вы покажете нам правильные и неправильные совпадения для вашего регулярного выражения.Это может помочь нам определить, действительно ли требуется ваше регулярное выражение. –

+0

отредактирован, чтобы включить более подробную информацию. – iniki

ответ

3

Регулярное выражение будет намного быстрее, если вы его переписать так:

Regex regex = new Regex(@"^\d+(\.\d*)? \d+(\.\d*)? \d+(\.\d*)? SRGB$"); 

Примечание два важных изменения:

  1. Каждый . маскируется обратной косой черты, так что регулярное выражение соответствует буквальная точка вместо любого символа.
  2. Каждый \. и следующие \d* являются необязательными в качестве группы, а не \., являющиеся необязательными сами по себе.

Оригинальный регулярное выражение является медленным, поскольку \d+.?\d* содержит последовательные quantifiers (+, ? и *). Это вызывает чрезмерное значение backtracking, когда механизм регулярных выражений пытается совместить строку, начинающуюся с длинной последовательности цифр. На моей машине, например, линия, содержащая 10 000 нулей, занимает больше, чем четыре секунды для соответствия. Пересмотренное регулярное выражение занимает менее четыре миллисекунды, улучшение 1000x.

Регулярное выражение может быть даже быстрее (волоском), если вы передаете

RegexOptions.Compiled | RegexOptions.ECMAScript 

в качестве второго аргумента Regex конструктора. ECMAScript сообщает двигателю регулярного выражения обрабатывать \d как [0-9], игнорируя цифры Unicode, такие как 7 (тибетский 7), которые вам не нужны.

+0

Очень приятное объяснение Майкл. – Kevin

0

В зависимости от формата записи вы можете анализировать быстрее, чем при использовании регулярного выражения. Не зная всего о вашем файле, но из ваших двух примеров это примерно на 30% быстрее, чем использование оптимизированного регулярного выражения.

 decimal r; 
     decimal g; 
     decimal b; 
     string rec; 
     string[] fields; 
     List<RGBColour> originalColourList = new List<RGBColour>(); 

     using (StreamReader sr = new StreamReader(@"c:\temp\rgb.txt")) 
     { 
      while (null != (rec = sr.ReadLine())) 
      { 
       if (rec.EndsWith("SRGB")) 
       { 
        fields = rec.Split(' '); 

        if (fields.Length == 4 
         && decimal.TryParse(fields[0], out r) 
         && decimal.TryParse(fields[1], out g) 
         && decimal.TryParse(fields[2], out b) 
         && (r+g+b !=0) 
         && (r != 1 && g != 1 && b!=1) 
         ) 
        { 
         RGBColour rgbColour = new RGBColour() { Red = r, Green = g, Blue = b }; 
         originalColourList.Add(rgbColour); 
        } 
       } 
      } 
     } 

Условный будет короткое замыкание, как только любой из критериев, являются ложными, и если все это правда, что вы больше не должны преобразовать все значения в десятичные. Я проанализировал 6 миллионов строк с этим примерно за 12,5 секунды.

Смежные вопросы