[PATTERN MATCHING]

N

Nicolas Vautier

Hey guys,

Let's say that I have this:

$line =~ s/$pattern/$replacement/;

It should find every $pattern in $line and replace it by $replacement
right?

But since I have characters such as "|", """, "'", "!", "?" in my
strings, it has a very strange behavior.

Is there any way to specify perl NOT TO USE regular expressions in my
example?

Thanks for your help,
Nico
 
G

Glenn Jackman

At 2004-12-17 02:14PM said:
Let's say that I have this:

$line =~ s/$pattern/$replacement/;

It should find every $pattern in $line and replace it by $replacement
right?

But since I have characters such as "|", """, "'", "!", "?" in my
strings, it has a very strange behavior.

Is there any way to specify perl NOT TO USE regular expressions in my
example?

perldoc -f quotemeta

$line =~ s/\Q$pattern/$replacement';
 
A

A. Sinan Unur

Subject: [PATTERN MATCHING]

Please don't shout.
Let's say that I have this:

$line =~ s/$pattern/$replacement/;

It should find every $pattern in $line and replace it by $replacement
right?

But since I have characters such as "|", """, "'", "!", "?" in my
strings, it has a very strange behavior.

See

perldoc perlop

Is there any way to specify perl NOT TO USE regular expressions in my
example?

Sure you could do search and replace without regular expressions but it
would be very tedious and bug prone. Why do you want to do that?

Sinan
 
J

Juha Laiho

Nicolas Vautier said:
Let's say that I have this:

$line =~ s/$pattern/$replacement/;

It should find every $pattern in $line and replace it by $replacement
right?

But since I have characters such as "|", """, "'", "!", "?" in my
strings, it has a very strange behavior.

Is there any way to specify perl NOT TO USE regular expressions in my
example?

I think you're after \Q and \E - as in

$line =~ s/\Q$pattern\E/$replacement/;

See 'perldoc perlre' for explanation.
 
N

niko

That's exactly what I want to do.
Not using regular expressions.
Because in the example, when $pattern="super.test?\nothin" and
$replacement="another?greatte\st", it obviously doesn't work properly.
Thanks for your reply,
Nico
 
N

niko

Is there any way to specify perl NOT TO USE regular expressions in
my
Sure you could do search and replace without regular expressions but it
would be very tedious and bug prone. Why do you want to do that?

Because my two strings contain characters used in regular expressions
such as ?.|\ ...
What could make perl considering those characters as characters like
others?

Thx,
Nico
 
A

A. Sinan Unur

That's exactly what I want to do.
Not using regular expressions.
Because in the example, when $pattern="super.test?\nothin" and
$replacement="another?greatte\st", it obviously doesn't work properly.

No, it looks like what you want to do is keep using regular expressions but
have some special characters not be special.

Based on your problem description, I am not sure you want those double-
quotes in

my $pattern="super.test?\nothin";

either.

Please do read

perldoc perlop

Sinan
 
G

Gunnar Hjalmarsson

Nicolas said:
Let's say that I have this:

$line =~ s/$pattern/$replacement/;

It should find every $pattern in $line and replace it by $replacement
right?

No, it should find *the first occurrence of* $pattern in $line and
replace it. You need the /g modifier to replace *every* of something.
But since I have characters such as "|", """, "'", "!", "?" in my
strings, it has a very strange behavior.

Is there any way to specify perl NOT TO USE regular expressions in my
example?

Others have pointed you to this solution:

$line =~ s/\Q$pattern/$replacement/;

which makes the left side of the s/// operator treat $pattern as a
string. OTOH, using the regex engine for searching and replacing strings
is not very efficient, and a combination of the substr() and index()
functions can be used instead:

substr $line, index($line, $pattern), length $pattern, $replacement;

If you actually need multiple substitutions, this would work:

{
local $[ = 1;
while ( my $pos = index $line, $pattern ) {
substr $line, $pos, length $pattern, $replacement;
}
}

See "perldoc -f substr" and "perldoc -f index".
 
G

Gunnar Hjalmarsson

A. Sinan Unur said:
Sure you could do search and replace without regular expressions but it
would be very tedious and bug prone.

In what way would searching and replacing *strings* without the regex
engine be "tedious and bug prone"?

See my other post in this thread.
 
A

A. Sinan Unur

In what way would searching and replacing *strings* without the regex
engine be "tedious and bug prone"?

Well, I thought of posting a similar routine for the purposes of this
question but then decided against it. While that method works for the
specific case we are talking about, it becomes unwieldy very fast the
moment you introduce even the simplest pattern matching features we take
for granted.

I did not mean to imply, although it does come across that way, that
searching and replacing plain strings is that hard.

However, if you do want an example of a bug with the code you posted:

#! perl

use strict;
use warnings;

my $text = q{I would like to replace Gunnar's name with my name.};

my $search = 'Tad';
my $replace = 'Sinan';

substr $text, index($text, $search), length $search, $replace;

print $text;

__END__

D:\Home>perl s.pl
I would like to replace Gunnar's name with my nameSinan

I know, I know, it is a cheap shot :) But it is a bug nevertheless. You do
need to remember to check if the match actually succeeded.

Sinan.
 
A

A. Sinan Unur

If you actually need multiple substitutions, this would work:

{
local $[ = 1;
while ( my $pos = index $line, $pattern ) {
substr $line, $pos, length $pattern, $replacement;
}
}

Opps. I did not read this far down in my reply to your other message.
Apologies.

Sinan.
 
A

A. Sinan Unur

If you actually need multiple substitutions, this would work:

{
local $[ = 1;
while ( my $pos = index $line, $pattern ) {
substr $line, $pos, length $pattern, $replacement;
}
}

Opps. I did not read this far down in my reply to your other message.
Apologies.

On second thought, another cheap shot:

#! perl

use strict;
use warnings;

my $line = 'Sinan';
my $pattern = 'Sinan';
my $replacement = 'A. Sinan Unur';

{
local $[ = 1;
while ( my $pos = index $line, $pattern ) {
substr $line, $pos, length $pattern, $replacement;

}
}

print $line;

__END__


Sinan
 
G

Gunnar Hjalmarsson

A. Sinan Unur said:
However, if you do want an example of a bug with the code you posted:

#! perl

use strict;
use warnings;

my $text = q{I would like to replace Gunnar's name with my name.};

my $search = 'Tad';
my $replace = 'Sinan';

substr $text, index($text, $search), length $search, $replace;

print $text;

__END__

D:\Home>perl s.pl
I would like to replace Gunnar's name with my nameSinan

I know, I know, it is a cheap shot :)

Not cheap at all. The single substitution variant should better be
something like:

if ( ( my $pos = index $line, $pattern ) >= 0 ) {
substr $line, $pos, length $pattern, $replacement;
}

Thanks for pointing it out!

Btw, the multiple substitution should be:

while ( ( my $pos = index $line, $pattern ) >= 0 ) {
substr $line, $pos, length $pattern, $replacement;
}

to prevent the need to fiddle with the $[ variable.
But it is a bug nevertheless. You do
need to remember to check if the match actually succeeded.

Yep.
 
G

Gunnar Hjalmarsson

A. Sinan Unur said:
On second thought, another cheap shot:

#! perl

use strict;
use warnings;

my $line = 'Sinan';
my $pattern = 'Sinan';
my $replacement = 'A. Sinan Unur';

{
local $[ = 1;
while ( my $pos = index $line, $pattern ) {
substr $line, $pos, length $pattern, $replacement;

}
}

print $line;

__END__

Yeah, *that* was cheap. :) Well, I never said you don't need to be
attentive to what you are doing when playing with substr() and index().
Just that it may be more efficient...
 
A

A. Sinan Unur

....

Yeah, *that* was cheap. :)

....

I know, I know.
Well, I never said you don't need to be attentive to what you are doing
when playing with substr() and index(). Just that it may be more
efficient...

Mine was just an indirect way of trying to fix the OP's terminology and
also guide him toward a document which he should benefit from by reading in
its entirety.

I suspect that the OP's problem may involve inappropriate (or
inconsistent) use of double quotes as well as failing to quote the regex-
special characters, but this is just a suspicion since the OP did not show
real code and real data.

I did originally think about posting an index/substr based solution but too
many special cases kept pop up in my mind. Then I remembered Sedgewick's
treatment of search and replace in C, and I gave up.

Hope you had fun. I did :)

Sinan.
 
J

jl_post

Nicolas said:
Let's say that I have this:

$line =~ s/$pattern/$replacement/;

It should find every $pattern in $line and replace it by $replacement
right?

No. It will replace only the first occurrence of $pattern (if at
least one exists) with $replacement. To replace every occurrence, use
the /g switch, like this:

$line =~ s/$pattern/$replacement/g;
But since I have characters such as "|", """, "'", "!", "?" in my
strings, it has a very strange behavior.

Is there any way to specify perl NOT TO USE regular expressions in my
example?

Yes. Others posters have (correctly) said:

$line =~ s/\Q$pattern\E/$replacement/;

but you can also "backslash" the special characters (like "|", """,
"'", "!", "?") with the quotemeta() function. This function will
return a new pattern that you can use that has all the special
characters escaped (so that they won't interfere with the regular
expression matching). You use it like this:

my $escapedPattern = quotemeta($pattern);
$line =~ s/$escapedPattern/$replacement/g;

In other words, if you have the line:

print quotemeta("Again? (y/n)");

you'll see the output:

Again\?\ \(y\/n\)

meaning that if you use that output in a pattern match, the "?", "(",
and ")" characters won't affect how you match a pattern.

Note that, according to "perldoc -f quotemeta", the line:

my $escapedPattern = quotemeta($pattern);

is equivalent to:

my $escapedPattern = "\Q$pattern\E";

which makes the following regular expression substitutions equivalent:

my $escapedPattern = quotemeta($pattern);
$line =~ s/$escapedPattern/$replacement/g;

$line =~ s/\Q$pattern\E/$replacement/g;

Which method should you use? In my opinion, you should use
whichever one you find more readable and easier to understand. And of
course, that part depends on you.
I hope this helps, Nicolas.

-- Jean-Luc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top