473,396 Members | 1,757 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Problem with boost::regex_replace

I hope a Boost question is not too off-topic here. It seems that
upgrading to Boost 1.33 broke some old regex code that used to work. I
have reduced the problem to this simple example:

cout << boost::regex_replace(string("foo"),
boost::regex(".*"),
string("bar")) << endl;

The above code prints "barbar" where I expect "bar". Can anyone shed
some light on this? It used to work with 1.30 (though regex_replace
was called regex_merge). It seems to me that ".*" should match all of
"foo" and replace it with "bar", so where does the second "bar" in
"barbar" come from?

Through trial and error I discovered that adding boost::match_not_null
to the normal boost::match_default flag restores the desired behavior,
but I'm not sure if this is significant or just coincidence.

Derek

Oct 5 '05 #1
7 7769

de**********@grog.net wrote:
I hope a Boost question is not too off-topic here. It seems that
upgrading to Boost 1.33 broke some old regex code that used to work. I
have reduced the problem to this simple example:

cout << boost::regex_replace(string("foo"),
boost::regex(".*"),
string("bar")) << endl;

The above code prints "barbar" where I expect "bar". Can anyone shed
some light on this? It used to work with 1.30 (though regex_replace
was called regex_merge). It seems to me that ".*" should match all of
"foo" and replace it with "bar", so where does the second "bar" in
"barbar" come from?

Through trial and error I discovered that adding boost::match_not_null
to the normal boost::match_default flag restores the desired behavior,
but I'm not sure if this is significant or just coincidence.

The ".*" expression matches zero or more characters. The "zero" means
it doesn't need any characters to make a match; so when there are zero
characters left to search, the patttern finds another match.

Because it matches no string at all, a .* search pattern is rarely the
best choice. It's more likely that the regex expression .+ is the
intended search string.

Greg

Oct 6 '05 #2
Greg wrote:
I hope a Boost question is not too off-topic here. It
seems that upgrading to Boost 1.33 broke some old regex
code that used to work. I have reduced the problem to
this simple example:

cout << boost::regex_replace(string("foo"),
boost::regex(".*"),
string("bar")) << endl;

The above code prints "barbar" where I expect "bar".
Can anyone shed some light on this? It used to work
with 1.30 (though regex_replace was called regex_merge).
It seems to me that ".*" should match all of "foo" and
replace it with "bar", so where does the second "bar" in
"barbar" come from?

Through trial and error I discovered that adding
boost::match_not_null to the normal boost::match_default
flag restores the desired behavior, but I'm not sure if
this is significant or just coincidence.


The ".*" expression matches zero or more characters. The
"zero" means it doesn't need any characters to make a
match; so when there are zero characters left to search,
the patttern finds another match.

Because it matches no string at all, a .* search pattern
is rarely the best choice. It's more likely that the regex
expression .+ is the intended search string.


Thanks, Greg. Your explanation is precisely why I thought adding the
boost::match_not_null flag fixed the problem -- because it "specifies
that the expression can not be matched against an empty sequence."
Unfortunately that explanation seems contradicted by this example,
which is my original example with the empty sequence "" as input
instead of "foo":

cout << boost::regex_replace(string(""), // empty sequence
boost::regex(".*"),
string("bar")) << endl;

By your reasoning the ".*" should match the empty input sequence "" and
the output should be "bar". However, the output I get is the empty
sequence "", not "bar".

I am also bothered that in other languages I routinely use -- and in
previous versions of Boost -- the expression ".*" does not match the
empty sequence. It all seems very inconsistent.

Oct 6 '05 #3
de**********@grog.net wrote:
Greg wrote:
I hope a Boost question is not too off-topic here. It
seems that upgrading to Boost 1.33 broke some old regex
code that used to work. I have reduced the problem to
this simple example:

cout << boost::regex_replace(string("foo"),
boost::regex(".*"),
string("bar")) << endl;

The above code prints "barbar" where I expect "bar".
Can anyone shed some light on this? It used to work
with 1.30 (though regex_replace was called regex_merge).
It seems to me that ".*" should match all of "foo" and
replace it with "bar", so where does the second "bar" in
"barbar" come from?

Through trial and error I discovered that adding
boost::match_not_null to the normal boost::match_default
flag restores the desired behavior, but I'm not sure if
this is significant or just coincidence.


The ".*" expression matches zero or more characters. The
"zero" means it doesn't need any characters to make a
match; so when there are zero characters left to search,
the patttern finds another match.

Because it matches no string at all, a .* search pattern
is rarely the best choice. It's more likely that the regex
expression .+ is the intended search string.


Thanks, Greg. Your explanation is precisely why I thought adding the
boost::match_not_null flag fixed the problem -- because it "specifies
that the expression can not be matched against an empty sequence."
Unfortunately that explanation seems contradicted by this example,
which is my original example with the empty sequence "" as input
instead of "foo":

cout << boost::regex_replace(string(""), // empty sequence
boost::regex(".*"),
string("bar")) << endl;

By your reasoning the ".*" should match the empty input sequence "" and
the output should be "bar". However, the output I get is the empty
sequence "", not "bar".


I am not able to reproduce this behavior with the default boost
configuration. The above line of code does output "bar" with boost 1.33
on my machine. Note that there is an unspecified default argument which
should be boost::match_default. In other words, the above line should
be equivalent to this statement:

cout << boost::regex_replace(string(""), // empty sequence
boost::regex(".*"),
string("bar"),
boost::match_default) << endl;

Replacing "boost::match_default" with "boost::match_not_null" or with
"boost:: match_not_dot_null" changes the output to a zero-length
string, as expected.

You may wish to run the boost::regex test suite that is part of the
distribution to ensure that your build was properly compiled.

Greg

Oct 6 '05 #4
Greg wrote:

The ".*" expression matches zero or more characters. The "zero" means
it doesn't need any characters to make a match; so when there are zero
characters left to search, the patttern finds another match.

Because it matches no string at all, a .* search pattern is rarely the
best choice. It's more likely that the regex expression .+ is the
intended search string.


However, under the maximum munch rule, in an otherwise unconstrained
search like the one at issue it should match the entire target sequence.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Oct 6 '05 #5
Greg wrote:
I am not able to reproduce this behavior with the default boost
configuration. The above line of code does output "bar" with boost 1.33
on my machine. Note that there is an unspecified default argument which
should be boost::match_default. In other words, the above line should
be equivalent to this statement:

cout << boost::regex_replace(string(""), // empty sequence
boost::regex(".*"),
string("bar"),
boost::match_default) << endl;

Replacing "boost::match_default" with "boost::match_not_null" or with
"boost:: match_not_dot_null" changes the output to a zero-length
string, as expected.

You may wish to run the boost::regex test suite that is part of the
distribution to ensure that your build was properly compiled.

Greg


You are quite right; I'm not sure why it didn't work before, but I
re-compiled my example and sure enough ".*" does indeed match the empty
string. That is, the folowing code outputs "bar":

cout << regex_replace(string(""), // empty sequence
regex(".*"),
string("bar"),
match_default) << endl;

However, going back to the original example, I'm still confused about
one thing. Recall that the following code outputs "barbar":

cout << regex_replace(string("foo"),
regex(".*"),
string("bar"),
match_default) << endl;

So if I understand everything you've said, ".*" matches "foo" and
replaces it with "bar", and then it matches the remaining empty
sequence and outputs "bar" again (hence "barbar"). However, as Mr.
Becker points out, the "maximum munch" rule suggests that the ".*"
should consume "foo" *and* the empty sequence that implicitly follows,
right? It seems to me that the "maximum munch" rule suggests the
output should be "bar", not "barbar".

Oct 6 '05 #6
de**********@grog.net wrote:

So if I understand everything you've said, ".*" matches "foo" and
replaces it with "bar", and then it matches the remaining empty
sequence and outputs "bar" again (hence "barbar"). However, as Mr.
Becker points out, the "maximum munch" rule suggests that the ".*"
should consume "foo" *and* the empty sequence that implicitly follows,
right? It seems to me that the "maximum munch" rule suggests the
output should be "bar", not "barbar".


No, the maximum munch rule consumes the three characters, leaving an
empty target string. The next attempt to match ".*" succeeds, so there
is a second match. Having just matched an empty string, the search
algorithm now requires a non-null match, which fails, and the search
terminates. So you should get "barbar", because you got two matches. At
least, that's what I currently think, but I'm at the C++ Standards
Committee meeting, and half listening to a discussion of concept
checking, so I don't promise that I've analyzed it correctly. However,
our implementation hit an infinite loop on your example because it
didn't force non-null for the search after an empty match, and once I
fixed that, I got the same result as you're seeing. <g>

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Oct 6 '05 #7
Pete Becker wrote:
So if I understand everything you've said, ".*" matches "foo" and
replaces it with "bar", and then it matches the remaining empty
sequence and outputs "bar" again (hence "barbar"). However, as Mr.
Becker points out, the "maximum munch" rule suggests that the ".*"
should consume "foo" *and* the empty sequence that implicitly follows,
right? It seems to me that the "maximum munch" rule suggests the
output should be "bar", not "barbar".


No, the maximum munch rule consumes the three characters, leaving an
empty target string. The next attempt to match ".*" succeeds, so there
is a second match. Having just matched an empty string, the search
algorithm now requires a non-null match, which fails, and the search
terminates. So you should get "barbar", because you got two matches. At
least, that's what I currently think, but I'm at the C++ Standards
Committee meeting, and half listening to a discussion of concept
checking, so I don't promise that I've analyzed it correctly. However,
our implementation hit an infinite loop on your example because it
didn't force non-null for the search after an empty match, and once I
fixed that, I got the same result as you're seeing.


Thanks for the explanation -- to you and Greg both. My world makes a
little more sense now.

Oct 6 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
by: Andrew Maclean | last post by:
I guess this problem can be distilled down to: How do I search through a string, find the first matching substring, replace it, and continue through the string doing this. Can replace_if() be used...
7
by: Aek | last post by:
Hi everyone, I am trying to construct a regular expression and format string to use with a boost::regex_replace() In my file the sample text is: // .fx shader file FLOAT JOE 3545f; FLOAT...
3
by: Yahooooooooo | last post by:
Hi, whats the issue in below code ... #include <iostream> #include <fstream> #include <sstream> #include <string> #include <iterator> #include <boost/regex.hpp>
1
by: Yahooooooooo | last post by:
Just practicing BOOST regular expressions....giving errors... -- wanted to replace SPACE with NULL. #include <iostream> #include <fstream> #include <sstream> #include <string> #include...
8
by: Marcus Kwok | last post by:
Is std::string::npos portably able to be incremented? For example, I want to insert some text into a string. If a certain character is found, I want to insert this text immediately after this...
8
by: g.vukoman | last post by:
Hi all, I asking me how to design my method. Should I use pointer only? Or references? Or Values? I don't know... Below is a small method to read the mem amount of a machine. Fell free to...
3
by: rottmanj | last post by:
In my application I get a string from my datasource that I need to replace some of the bad chars in the strings. Right now I have written a pretty standard regex that should replace any of the...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.