Нужна помощь с регулярным выражением, не заменяющим все экземпляры выражения

2

Я бил головой о стену в этот день весь день и приближаюсь к моему концу. Ищете новую перспективу.

Пример ввода текста:
 (разрывы строк добавлены для ясности, а не фактические данные)

</div>#My Novel<br />  
##Chapter1<br />  
It was a dark and stormy night<br />
##Chapter 2<br />
The End

Желаемый результат

</div><h1>My Novel</h1><br />
<h1>Chapter1</h1><br />  
It was a dark and stormy night<br />  
<h1>Chapter 2</h1><br />  
The End

Фактический выход

</div><h1>My Novel</h1><br />
##Chapter1<br />  
It was a dark and stormy night<br />  
<h1>Chapter 2</h1><br />  
The End

Вот выражение соответствия
(отформатированные для легкого чтения, комментарии /linebreaks не находятся в выражении)

(?<preamble>
    (                             
        ([<]\/\w+\d*[>])|([<]\w+\d*\s*\/[>])   #</tag> or <tag />
    )
    \s*  #optional whitespace                       
)

(?<hashmarks>
    \#{1,6}      #1-6 hash marks
)    

(?<content>
    .+?          #header content
 )      

(?<closing>
    ([<](br|\/\s*br|br\s*\/)[>])   #<br>,</br>, or <br />
)

Вот выражение Expression

${preamble}<h1>${content}</h1>${closing}

Если это важно, я использую следующую перезагрузку С# regex.replace:

Regex.Replace(Source,SrchExp,ReplExpr,RegexOptions.IgnoreCase)

Вопрос (наконец)
Кто-нибудь может понять, почему он заменяет #My Novel и ## Chapter 2, но не ## Chapter 1?

Извините за длинный пост, и, надеюсь, я не делал ничего, пытаясь отформатировать его, чтобы сделать его доступным для SO.

Обновление:

Еще одна вещь, которая может помочь. Добавление дополнительного тега разрыва сразу после "Романа" заставляет готовый код работать отлично. Пока не знаю, почему.

Пример ввода текста (изменен):

</div>#My Novel<br /><br />
##Chapter1<br />  
It was a dark and stormy night<br />
##Chapter 2<br />
The End
  • 0
    Почему ваши данные начинаются с </ div>, конечного тега?
  • 0
    Исходные входные данные обычно будут длиннее, но, поскольку я не сопоставляюсь ни с чем до первого конечного тега, я пропустил их в образце, чтобы их было легче читать. Если вам от этого легче, замените <br /> тэгом </ div>. Проблема идентична.
Теги:

1 ответ

2
Лучший ответ

Вот тот, который был фактически протестирован и, похоже, работает.

Проблема в том, что как только совпадение найдено, поиск продолжается точно там, где первый остановился. В результате закрытие <br /> of #My Novel больше не будет снято, и поэтому #Chapter1 будет пропущен.

Чтобы в любом случае записать конструкторы типа #Chapter1, мы можем использовать утверждение lookbehind. Lookbehinds обеспечивает наличие префикса, даже если оно продолжается до текущей позиции. Это также предотвращает необходимость отбросить его в строке замены:

  • Замените (?<preamble> на (?<=

  • Затем в заменяющей строке удалите часть ${preamble}.

Общее выражение поиска теперь выглядит следующим образом:

(?<=             # removed the preamble capture and replaced with a lookbehind
    (                             
        ([<]\/\w+\d*[>])|([<]\w+\d*\s*\/[>])   #</tag> or <tag />
    )
    \s*  #optional whitespace                               
)

(?<hashmarks>
    \#{1,6}      #1-6 hash marks
)    

(?<content>
    .+?          #header content
 )      

(?<closing>
    ([<](br|\/\s*br|br\s*\/)[>])   #<br>,</br>, or <br />
)

И строка замены выглядит так:

<h1>${content}</h1>${closing}

Наш результат теперь верно:

</div><h1>My Novel</h1><br />
<h1>Chapter1</h1><br />
It was a dark and stormy night<br />
<h1>Chapter 2</h1><br />
The End
  • 0
    Ты человек! Взгляд за кадром работал как шарм.
  • 0
    Вы также должны иметь возможность заменить (?<closing> прогнозом на будущее : (?=

Ещё вопросы

Сообщество Overcoder
Наверх
Меню