2009-12-05 3 views
1

Мне нужно найти в тексте все, что начинается с [и заканчивается], и заменить его значением, возвращаемым функцией. Итак, вот пример того, что я делаю:Замена коллекции соответствия регулярных выражений в C#

public string ProcessTemplate(string input) 
    { 
     return Regex.Replace(input, @"\[(.*?)\]", new MatchEvaluator(delegate(Match match) 
      { 
       return ProcessBlock(match.Result("$1")); 
      })); 
    } 

    public string ProcessBlock(string value) 
    { 
     return Block.FromString(value).Process(); 
    } 

Теперь моя проблема в том, когда мне нужно редактировать блоки. Поэтому я решил найти блоки, отредактировать их и , затем, заменив их в тексте.

Итак, я создал список блоков, и отделил метод ProcessTemplate двумя способами: FindBlocks и ReplaceBlocks:

public void FindBlocks(string input) 
    { 
     Input = input; 

     foreach (Match match in Regex.Matches(input, @"\[(.*?)\]")) 
      Blocks.Add(Block.FromString(match.Result("$1"))); 
    } 

    public string ReplaceBlocks() 
    { 
     string input = Input; 

     foreach (Block block in Blocks) 
      input = input.Replace("[" + block.OrginalText + "]", block.Process); 

     return input; 
    } 

    public IList<Block> Blocks 
    { 
     get; 
     set; 
    } 

    public string Input 
    { 
     get; 
     set; 
    } 

Это работает, но проблема заключается в том, что это довольно медленно. Я измерил с System.Diagnostics.Stopwatch каждой частью, и я узнал, что String.Replace в методе ReplaceBlocks довольно медленный.

Как его улучшить?

Спасибо.

+0

Я не понимаю, почему вы отказались от своего первого метода, который кажется правильным решением. Можете ли вы уточнить? –

+0

Право Марка: это именно то, для чего предназначен MatchEvaluator. Кроме того, если вы хотите, чтобы содержимое первой группы захвата, 'match.Groups [1]' намного эффективнее, чем 'match.Result (« $ 1 »)'. –

ответ

1

заменив строку в ReplaceBlock с StringBuilder может обеспечить увеличение производительности, как каждый раз, когда вы выполняете string.replace ему придется освободить строку и перераспределить строку. Строковый строитель не должен это делать.

Замените содержимое ReplaceBlock следующим.

// This will require a reference to System.Text 
StringBuilder input =new StringBuilder(Input); 
    foreach (Block block in Blocks) 
    { 
    input = input.Replace("[" + block.OrginalText + "]", block.Process); 
    } 
    return input.ToString(); 

Я также нашел замену петель foreach на цикл, который быстрее.

0

Я думаю, что это очень медленный процесс

Не оптимизировать, пока вы не профилированные. Узнайте, почему ваш код медленный, а затем оптимизируйте эти части.

http://c2.com/cgi/wiki?ProfileBeforeOptimizing

+0

См. Мои правки, пожалуйста. –

+0

Отлично! Одна вещь, которая может быть быстрее, состоит в том, чтобы сохранить смещения символа каждого блока, когда вы его первоначально сопоставляете. Затем замените этот диапазон символов с помощью подстроки, вместо того, чтобы использовать string.Replace - должно быть быстрее. Конечно, если ваш замененный контент не такой же длины, как и исходный контент, вам придется обновлять свои смещения с этой разницей после каждой замены. Больше бухгалтерии, но может быть быстрее в конце. – kevingessner

+0

@kevingessner: Я попытался: «input = input.Substring (0, block.Position) + block.Process() + input.Substring (block.Position + block.Length);" но он не работает ... block.Position = match.Index и block.Length = match.Length. Вы знаете, почему он не работает? –