Как исправить это многострочное регулярное выражение в Ruby?


У меня есть регулярное выражение в Ruby, которое не работает должным образом в многострочном режиме.

Я пытаюсь преобразовать текст Markdown в разметку Textile-eque, используемую в Redmine. Проблема заключается в моем регулярном выражении для преобразования блоков кода. Он должен найти любые строки, ведущие с 4 пробелами или табуляцией, а затем обернуть их в тегиpre .
markdownText = '# header

some text that precedes code

    var foo = 9;
    var fn = function() {}

    fn();

some post text'

puts markdownText.gsub!(/(^(?:s{4}|t).*?$)+/m,"<pre>n\1n</pre>")

Предполагаемый результат:

# header

some text that precedes code

<pre>
    var foo = 9;
    var fn = function() {}

    fn();
</pre>

some post text

Проблема заключается в том, что закрывающий тег pre печатается в конце документа вместо этого после " fn ();". Я попробовал некоторые варианты следующего выражения, но оно не соответствует:

gsub!(/(^(?:s{4}|t).*?$)+^(S)/m, "<pre>n\1n</pre>\2")

Как мне получить регулярное выражение, чтобы оно соответствовало только блоку кода с отступом? Вы можете проверить это регулярное выражение на Rubular здесь .

4 7

4 ответа:

Во-первых, обратите внимание, что 'm' многострочный режим в Ruby эквивалентен 's' однострочному режиму других языков. Другими словами; 'm' режим в Ruby означает: "точка соответствует всем".

Это регулярное выражение довольно хорошо справится с сопоставлением раздела кода типа markdown:

re = / # Match a MARKDOWN CODE section.
    (\r?\n)              # $1: CODE must be preceded by blank line
    (                    # $2: CODE contents
      (?:                # Group for multiple lines of code.
        (?:\r?\n)+       # Each line preceded by a newline,
        (?:[ ]{4}|\t).*  # and begins with four spaces or tab.
      )+                 # One or more CODE lines
      \r?\n              # CODE folowed by blank line.
    )                    # End $2: CODE contents
    (?=\r?\n)            # CODE folowed by blank line.
    /x
result = subject.gsub(re, '\1<pre>\2</pre>')

Это требует наличия пустой строки до и после раздела кода и позволяет использовать пустые строки внутри самого раздела кода. Он допускает либо \r\n, либо \n окончание строки. Обратите внимание, что это не раздевание первые 4 пробела (или табуляции) перед каждой строкой. Это потребует большей сложности кода. (Я не рубиновый парень, поэтому не могу помочь с этим.)

Я бы рекомендовал посмотреть на сам источник markdown, чтобы увидеть, как это действительно делается.

/ ^(\s{4} / \t)+.+\;\n$ / m

Работает немного лучше, но все равно берет новую строку, которая нам не нужна. здесь это на rubular.

Это работает для меня с вашим вводом образца.

markdownText.gsub(/\n?((\s{4}.+)+)/, "\n<pre>#{$1}\n</pre>")

Здесь Еще один, который захватывает все отступы линий в одном блоке

((?:^(?: {4}|\t)[^\n]*$\n?)+)