Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problem: perl negative look-ahead assertion in multi-line mode

85 views
Skip to first unread message

cibalo

unread,
May 22, 2013, 5:51:20 AM5/22/13
to
Hello,
I have updated/modified my mysql database in my free website recently.
I have to re-code all my php files such that an extra statement has to
be inserted before the last mysql_query call. It may have more than
one mysql_query call in some of my php files.

I try to use a negative look-ahead assertion to make such a change as
follows.

I would like to insert just one "new_insert" line before the "coding
line 4". And my php file looks like this.

$ echo -e "coding line 1 test 1\ncoding line 2 mysql_query 2\ncoding
line 3 test 3\ncoding line 4 mysql_query 4\ncoding line 5 test 5"
coding line 1 test 1
coding line 2 mysql_query 2
coding line 3 test 3
coding line 4 mysql_query 4
coding line 5 test 5

Then I perl-regex with negative look-ahead assertion in multi-line
mode (/smg or /sg or /mg) like this:

$ echo -e "coding line 1 test 1\ncoding line 2 mysql_query 2\ncoding
line 3 test 3\ncoding line 4 mysql_query 4\ncoding line 5 test 5" |
perl -pe '/mysql_query(?!.*mysql_query)/smg && print "new_insert\n"'
coding line 1 test 1
new_insert
coding line 2 mysql_query 2
coding line 3 test 3
new_insert
coding line 4 mysql_query 4
coding line 5 test 5

However, my "coding line 2" gets changed too. And that is not what I'm
looking for.

Or, perl negative look-ahead assertion doesn't like me! Can you please
let me know what I'm missing?

Thank you very much in advance!!!

Best Regards,
cibalo

Christian Winter

unread,
May 22, 2013, 8:37:21 AM5/22/13
to
In this case its not the look-ahead that's breaking things.
You're starting with a wrong assumption by running Perl with
the "-p" option, thus doing line-by-line processing of your
input. To be able to look ahead, the whole input must already
be known to your script, so you have to slurp your whole file
in one go (see "perldoc perlrun" for details):
echo ... | perl -0777 -pe ...

Now that you have the whole input in $_, you need to do regex
replacement instead of just matching to get your insert at the
correct place:

perl -0777 -pe 's/(mysql_query(?!.*mysql_query))/new_insert\n$1/sm'

You don't need the "g" modifier, as the replacement only needs
to happen once.

HTH
Chris

F'up to clpm set

Charles DeRykus

unread,
May 22, 2013, 5:47:37 PM5/22/13
to
Since you want to insert just before the last mysql_query line, you can
use .* greediness to avoid a negative look-ahead:

echo ... |
perl -0777 -pe 's/ (.*) (coding .*? query .*? \n)/$1new_insert\n$2/sx'


--
Charles DeRykus

cibalo

unread,
May 22, 2013, 11:32:30 PM5/22/13
to
Hello Christian Winter And Charles DeRykus:

Thank you very much for your valuable reply.
Your perl regex works great in my test example.

However, it fails in real cases, because the beginning of the "mysql_query" line is not fixed.

My real mysql_query statement might look like this.
mysql_query($sql,$con);
if (mysql_query($sql,$con)) { ...
$result = mysql_query($query);

cibalo

unread,
May 23, 2013, 2:11:21 AM5/23/13
to
Hello,

On Thursday, May 23, 2013 5:47:37 AM UTC+8, Charles DeRykus wrote:
> Since you want to insert just before the last mysql_query line, you can>
> use .* greediness to avoid a negative look-ahead:>
> echo ... |
>
> perl -0777 -pe 's/ (.*) (coding .*? query .*? \n)/$1new_insert\n$2/sx'>
> Charles DeRykus

I get your idea now. I can get the result with greedy+non-greedy match as follows.
$ echo -e "aa coding line 1 test 1\nbb coding line 2 mysql_query 2\ncc coding line 3 test 3\ndd coding line 4 mysql_query 4\nee coding line 5 test 5"|perl -0777 -pe 's/(.*) (\n .*? mysql_query .*? \n) /$1\nnew_insert$2/sx'
aa coding line 1 test 1
bb coding line 2 mysql_query 2
cc coding line 3 test 3
new_insert
dd coding line 4 mysql_query 4
ee coding line 5 test 5

Rainer Weikusat

unread,
May 23, 2013, 10:33:54 AM5/23/13
to
cibalo <cib...@gmx.co.uk> writes:
> I have updated/modified my mysql database in my free website recently.
> I have to re-code all my php files such that an extra statement has to
> be inserted before the last mysql_query call. It may have more than
> one mysql_query call in some of my php files.
>
> I try to use a negative look-ahead assertion to make such a change as
> follows.
>
> I would like to insert just one "new_insert" line before the "coding
> line 4". And my php file looks like this.
>
> $ echo -e "coding line 1 test 1\ncoding line 2 mysql_query 2\ncoding
> line 3 test 3\ncoding line 4 mysql_query 4\ncoding line 5 test 5"
> coding line 1 test 1
> coding line 2 mysql_query 2
> coding line 3 test 3
> coding line 4 mysql_query 4
> coding line 5 test 5

Strictly, this isn't related to the shell and not related to Perl, but
if you want to make a modification to a set of text files, have you
considered using a text editor?

NB: The 'compound command' below was executed in a directory which
contained three copies of the 'demo file' whose content was included in
the original posting.

for x in *; do
ed "$x" <<'TT'
$
?mysql_query?i
new_insert
.
wq
TT
done

This invokes ed on every file in the current directory, with 'command
input' coming from a here document (separator quoted to prevent 'shell
expansion' of the text). The ed commands are

$

Go to the last line of the input file.

?mysql_query?i

Search backwards (regexp) for the first msql_query and insert text in
front of that line.

new_insert

The text to insert.

.

'Exit insert-mode' command.

wq

Write changes and quit (non-standard, BSD-originated command).

cibalo

unread,
May 23, 2013, 10:31:36 PM5/23/13
to
Hello,

Thank you very much for your valuable reply.

You Know You're Right. ed can do the same job.

On Thursday, May 23, 2013 10:33:54 PM UTC+8, Rainer Weikusat wrote:
> if you want to make a modification to a set of text files, have you>
> considered using a text editor?
> for x in *; do>
> ed "$x" <<'TT'>
> $
> ?mysql_query?i
> new_insert
> .
> wq
> TT
> done

For testing your algorithm, I do the followings.

$ echo -e "aa coding line 1 test 1\nbb coding line 2 mysql_query 2\ncc coding line 3 test 3\ndd coding line 4 mysql_query 4\nee coding line 5 test 5" > edtest

$ ed edtest <<< $'?mysql_query?i\nnew_insert\n.\n%p\nq'
134
aa coding line 1 test 1
bb coding line 2 mysql_query 2
cc coding line 3 test 3
new_insert
dd coding line 4 mysql_query 4
ee coding line 5 test 5
?
$

It works!!!
0 new messages