regex - Change text block with nearest search pattern - Stack Overflow
I want to search and replace a textblock:
- Find by start-pattern and end-pattern
- copy&paste the found block with changing the end-pattern.
I tried with perl -0777 -pe 's/(section:[\s\S]*?"MARKER")/\$1 =~ s/"MARKER"/"NEW MARKER"/gr/e' input.txt
(I know, it doesn't work as expected)
Curious about answers :-)
My textfile is like this:
active: true
sections:
- others: "a"
othersa: "aa"
- section:
- addPermissions: []
attribute: "attrA"
permission: "permA"
a: "this is some text"
value: "MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M7"
- section:
- addPermissions: []
attribute: "attrB"
value: "MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M8"
- section:
- addPermissions: []
a: "this is some text"
value: "M9"
- section:
- addPermissions: []
permission: "permC"
d: "this is some text"
value: "MARKER"
I want to search a block, where
- starts with "- section:"
- "- section:" is followed by "value: "MARKER""
The found block shall be copie&pasted behind itself having "MARKER" replaced by "NEW MARKER".
The result shall be like:
active: true
sections:
- others: "a"
othersa: "aa"
- section:
- addPermissions: []
attribute: "attrA"
permission: "permA"
a: "this is some text"
value: "MARKER"
- section:
- addPermissions: []
attribute: "attrA"
permission: "permA"
a: "this is some text"
value: "NEW MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M7"
- section:
- addPermissions: []
attribute: "attrB"
value: "MARKER"
- section:
- addPermissions: []
attribute: "attrB"
value: "NEW MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M8"
- section:
- addPermissions: []
a: "this is some text"
value: "M9"
- section:
- addPermissions: []
permission: "permC"
d: "this is some text"
value: "MARKER"
- section:
- addPermissions: []
permission: "permC"
d: "this is some text"
value: "NEW MARKER"
I want to search and replace a textblock:
- Find by start-pattern and end-pattern
- copy&paste the found block with changing the end-pattern.
I tried with perl -0777 -pe 's/(section:[\s\S]*?"MARKER")/\$1 =~ s/"MARKER"/"NEW MARKER"/gr/e' input.txt
(I know, it doesn't work as expected)
Curious about answers :-)
My textfile is like this:
active: true
sections:
- others: "a"
othersa: "aa"
- section:
- addPermissions: []
attribute: "attrA"
permission: "permA"
a: "this is some text"
value: "MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M7"
- section:
- addPermissions: []
attribute: "attrB"
value: "MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M8"
- section:
- addPermissions: []
a: "this is some text"
value: "M9"
- section:
- addPermissions: []
permission: "permC"
d: "this is some text"
value: "MARKER"
I want to search a block, where
- starts with "- section:"
- "- section:" is followed by "value: "MARKER""
The found block shall be copie&pasted behind itself having "MARKER" replaced by "NEW MARKER".
The result shall be like:
active: true
sections:
- others: "a"
othersa: "aa"
- section:
- addPermissions: []
attribute: "attrA"
permission: "permA"
a: "this is some text"
value: "MARKER"
- section:
- addPermissions: []
attribute: "attrA"
permission: "permA"
a: "this is some text"
value: "NEW MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M7"
- section:
- addPermissions: []
attribute: "attrB"
value: "MARKER"
- section:
- addPermissions: []
attribute: "attrB"
value: "NEW MARKER"
- section:
- addPermissions: []
a: "this is some text"
value: "M8"
- section:
- addPermissions: []
a: "this is some text"
value: "M9"
- section:
- addPermissions: []
permission: "permC"
d: "this is some text"
value: "MARKER"
- section:
- addPermissions: []
permission: "permC"
d: "this is some text"
value: "NEW MARKER"
Share
Improve this question
edited 8 hours ago
Carsten
asked yesterday
CarstenCarsten
394 bronze badges
6
- Is this YAML? If it is, you should use a parser. – TLP Commented yesterday
- it is yaml, but I don't have enough skills to solve it this way :-( – Carsten Commented yesterday
- 1 If you post the proper YAML input, someone might be able to fix it for you. But the YAML module isn't exactly complicated, just use and Load. I tried it with your current input, but it did not work properly. – TLP Commented yesterday
- I had to edit the test data: all blocks start with "- section:". Due to this change the result has changed. – Carsten Commented yesterday
- Well, the YAML parser dies on line 3, so... that is not valid yaml. – TLP Commented yesterday
3 Answers
Reset to default 2Your code is:
perl -0777 -pe 's/(section:[\s\S]*?"MARKER")/\$1 =~ s/"MARKER"/"NEW MARKER"/gr/e' input.txt
This appears to be attempting a nested substitution.
With /e
flag, RHS is actual code, so $
should not be escaped:
perl -0777 -pe 's/(section:[\s\S]*?"MARKER")/$1 =~ s/"MARKER"/"NEW MARKER"/gr/e' input.txt
Conversely, delimiters for nested s///
must be escaped (or different):
perl -0777 -pe 's/(section:[\s\S]*?"MARKER")/$1 =~ s\/"MARKER"\/"NEW MARKER"\/gr/e' input.txt
However, this replaces "section...MARKER" by just "NEW MARKER", which is not what seems to be wanted.
Instead, it is simpler to make use of the capture group directly:
perl -0777 -pe 's/(section:[\s\S]*?)"MARKER"/$1"NEW MARKER"/g' input.txt
or use a lookaround:
perl -0777 -pe 's/section:[\s\S]*?\K"MARKER"/"NEW MARKER"/g' input.txt
Thank you very much for providing examples and explanations! Finally I will use it like this (wrong search result):
perl -0777 -pe 's/(- section:[\s\S]*?)"MARKER"/$1"MARKER"\n$1"NEW MARKER 2"\n$1"NEW MARKER 3"/g' input.txt
My goal was to find the first block and duplicate it with different value: "MARKER"
.
Unfortunately, I had to adjust test data. Failure: block used as "$1" is much larger then expected. Block with value: "m7" has been duplicated, what was not intended.
Final result:
Some content ...
- section:
this is some text
this is some more text
value: "MARKER"
- section:
this is some text
this is some more text
value: "NEW MARKER 2"
- section:
this is some text
this is some more text
value: "NEW MARKER 3"
- section:
this is some text
this is some more text
value: "M7"
- section:
this is some text
this is some more text
value: "MARKER"
- section:
this is some text
this is some more text
value: "M7"
- section:
this is some text
this is some more text
value: "NEW MARKER 2"
- section:
this is some text
this is some more text
value: "M7"
- section:
this is some text
this is some more text
value: "NEW MARKER 3"
... content goes on
This matches the whole section by grabbing all the consecutive subsequent lines that are further indented than the first:
^ (\h+) - \h+ section: .* \n (?: \1 \h .* \n )*
Since we're getting the whole section, the marker doesn't need to be the last line of the section.
Putting that to use, we could do a search and replace in /e
as you did.
s{
^ (\h+) - \h+ section: .* \n (?: \1 \h .* \n )*
}{
my $section = $&;
if ( $section =~ /\bMARKER\b/ ) {
$section . ( $section =~ s/\bMARKER\b/NEWMARKER/gr )
} else {
$section
}
}xmeg;
But that's a lot of extra matches which can be avoided as follows:
s{
( ^ (\h+) - \h+ section: .* \n
(?: \2 \h .* \n )*
\2 \h .* \b ) MARKER ( \b .* \n
(?: \2 \h .* \n )* )
}{
$& . $1 . "NEW MARKER" . $3
}xmeg;
Note that you can use perl -gpe'...'
instead of perl -0777pe'...'
since 5.36.
- 芯片缺货严重,真凶或是ABF产能不足
- 微软要逆天!SurfacePhone能运行exe程序
- 黑客称用商业软件复制出德防长指纹
- Upgrading apache spark core from 3.3.2 to >=3.4.4 results in stackoverflowerror in logging - Stack Overflow
- python - Why does my plot have criss-crossing lines when I convert the index from string to datetime? - Stack Overflow
- tensorflow - How can I use training data into my custom metric? - Stack Overflow
- machine learning - Cannot import name 'T2TViTModel' from 'transformers' - Stack Overflow
- javascript - Responsiveness textContent (graphic) - Stack Overflow
- flutter - Uber category selection animation - Stack Overflow
- html - Disable scrolling. Overflow:hidden not working - Stack Overflow
- google bigquery - How to Load Large Tables Beyond the 10GB Query Limit in Power BI Premium? - Stack Overflow
- Compare two lists, one of them JSON, in SQLite - Stack Overflow
- java - jOOQ transaction does not work as expected - Stack Overflow
- Blockchain record extraction - Stack Overflow
- sockets - PICO WMicropython websocket client can't send to PHP websocket properly - Stack Overflow
- macos - Image from ImagePicker in landscape - Stack Overflow
- next.js - Update Server Component via a Client Component - Stack Overflow