nass nass - 1 year ago 71
Perl Question

matching multiple line string with perl regex and doing a replace

I have a source file where I use a macro to do logging. Typical logging lines look like:

STDOUT_LOG(logDEBUG4) << "a single line log text" << aVariable;

the exist some multiline log commands as well:

<< bsd->sensorName
<< " trainMinValueInWin = " << value.trough
<< " trainMaxValueInWin = " << value.peak
<< " |";

The idea is to grab the log string (whether it is in single line or multiple lines) and place them in the parenthesis of the macro.

Typically the end result would be something like:

STDOUT_LOG(logDEBUG4,"a single line log text" << aVariable);


<< " trainMinValueInWin = " << value.trough
<< " trainMaxValueInWin = " << value.peak
<< " |");

I am trying to read up on anything related to multiline matching, including while loops in perl, the
operators and potential ways to search and replace, but I am very far from correctly matching the multiline macro. I assume I need the /s operator in order for the "." to match newline characters too, but I have not been able to successfully use it.

The beginning of the pattern is of course "STDOUT_LOG" and the end is the first occurrence of ";" however many lines later it shows up.

this attempt

perl -ne 's/STDOUT_LOG\((.*?)\)(.*?)\;/STDOUT_LOG($1,$2)\;/gs; print;'

manages to pick up the log level ("logDEBUG4" in this case) is "sort" of OK for single line log commands, but matching of the rest of the lines fails even though I used the /s in the end.

How do I approach this problem? what other operators should I use? any good tutorials out there? ultimately is there a perl command that can save the day?

since none of the suggestions work out of the box for me (the pattern matching fails and as a result nothing is changed), I wonder if there is some newer functionality involved here. In any case my perl version is 5.18.2. I am trying to run the commands in a linux cli as follows:

perl -ne 's/pattern/replace/gs; print;' <filename>

I hope I am not doing something wrong here

Answer Source

In the end the command that successfully did what I wanted was the following:

perl -0777pne 's/STDOUT_LOG\((.*?)\)(.*?)<<(.*?);/STDOUT_LOG\(\1\,\2\3\);/gs' sensor.cpp

This is alot a superposition for the answers of "Federico Piazza" and "zdim". You'll notice I prepended the "STDOUT_LOG" bit in the front to really much exactly what I wanted in a large number of source files. I noticed that for correct matching one MUST include the /s operator at the end of the regex , but also add the -0777 flag in the perl executable.

see perlrun for an explanation of the runtime perl executable flags

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download