Регулярное выражение для несвязного соответствия между несколькими строками вплоть до строки, начинающейся с указанной строки c - PullRequest
2 голосов
/ 02 марта 2020

Я собираюсь ответить на это сам, но это дало мне приступы весь день, и хотя это объяснялось в другом месте, я думал, что я опубликую это с моим решением.

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

В демонстрационных целях я создал пример файла с функциями это сделало это для меня трудным:

начальный файл:

cat << EOF > test.txt
server {
    abcdefg blablablabla
    pizza
    #blablablabla
    blablablabla {
    zazazazazaza
    }
    turtles
    #}
    ninjas
    blablablabla

} #comments that might or might not be here

server {
    blablablabla
    blablablabla
    blablablabla
    blablablabla
}

zabzazab

EOF

Это был мой желаемый вывод. Обратите внимание, что скобка, с которой я сопоставляюсь, не является ни первым, ни последним вхождением закрывающей скобки. Его единственная отличительная особенность в том, что быть первым } в начале строки после начала моего матча:

server {
    wxyz

server {
    blablablabla
    blablablabla
    blablablabla
    blablablabla
} 

zabzazab

То, что я надеялся, сработает. Но slupring с 0777 убирает маркеры для начала и конца линии, так что это не сработало:

~#  perl -0777 -pe 's/(abcdefg(.*?)(^}.*$))/wxyz/gs' test.txt
server {
    abcdefg blablablabla
    pizza
    #blablablabla
    blablablabla {
    zazazazazaza
    }
    turtles
    #}
    ninjas
    blablablabla

} #comments that might or might not be here

server {
    blablablabla
    blablablabla
    blablablabla
    blablablabla
}

zabzazab

Сопоставление начала / конца линии, в то время как slupring также был точкой отсчета:

~# perl -0777 -pe 's/(abcdefg(.*?)(}))/wxyz/gs' test.txt
server {
    wxyz
    turtles
    #}
    ninjas
    blablablabla

} #comments that might or might not be here

server {
    blablablabla
    blablablabla
    blablablabla
    blablablabla
}

zabzazab


Так есть ли способ получить регулярное выражение для сопоставления между строкой и первым экземпляром {, который появляется в начале строки? Я тоже открыт для использования sed, но я полагал, что не жадный характер моего поиска сделает perl лучшим выбором.

Ответы [ 3 ]

2 голосов
/ 02 марта 2020

Как я понимаю вопрос, вы sh будете соответствовать части строки

server {
    abcdefg blablablabla
    pizza
    #blablablabla
    blablablabla {
    zazazazazaza
    }
    turtles
    #}
    ninjas
    blablablabla

} #comments that might or might not be here

server {
... blablablabla
}
...

, которая начинается "abcdefg" и заканчивается в конце строки, "} #comments that might or might not be here", при условии "abcdefg" начинает строку после отступа, и этой строке предшествует строка "server {". Затем вы замените другую строку для сопоставленного текста.

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

/^server +\{\s+(abcdefg.+?\n\}.*?$)/sm

demo

Флаг s позволяет .* соответствовать символам новой строки. Флаг m указывает синтаксическому анализатору обрабатывать якоря ^ и $ как начало и конец строки соответственно (предположительно, в отличие от начала и конца строки).

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

/
^server +\{\s+    # match 'server {` followed by 1+
                  #  whitespace chars
(                 # begin capture group 1
  abcdefg         # match literal
  .+?             # match 1+ chars, lazily
  \n              # match a newline
  \}              # match '}'
  .*?             # match 1+ chars, lazily
  $               # match end of line
)                 # end capture group 1
/smx              # single-line, multiline and free-
                  # spacing regex definition modes 
2 голосов
/ 02 марта 2020

Возможно, любая из следующих команд сделает это

perl -0777 -pe 's/abcdefg.*?(\nserver.*?)/wxyz\n$1/s' test.txt
perl -0777 -pe 's/abcdefg.*?server/wxyz\n\nserver/s' text.txt
perl -0777 -pe 's/abcdefg.*?}.*?}.*?}.*?\n/wxyz\n/s' test.txt
perl -0777 -pe 's/abcdefg(.*?}){3}.*?\n/wxyz\n/s' test.txt
perl -0777 -pe 's/abcdefg.*?\n}.*?\n/wxyz\n/s' test.txt

Вывод

server {
    wxyz

server {
    blablablabla
    blablablabla
    blablablabla
    blablablabla
}

zabzazab
0 голосов
/ 02 марта 2020

Кажется, мне нужны и флаги s, и m, и slurping:

~# perl -0777 -pe 's/(abcdefg(.+?)(\n}))/wxyz/sm' test.txt
server {
    wxyz #comments that might or might not be here

server {
    blablablabla
    blablablabla
    blablablabla
    blablablabla
}

Я до сих пор не совсем понимаю, зачем мне нужен и модификатор m, и slurping. Так что, если у кого-то есть лучший ответ, я отмечу его вместо моего.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...