Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Subsitution in loop

Status
Not open for further replies.

andreb7

Programmer
Oct 23, 2007
3
FR
Hi everyone
I'm frsutrated by this problem and would really appreciate a hand. I may not be doing this the best way, so any suggestions are more than welcome...I want to replace certain sections of a string with other sections (substring replacements).

For example, I would like to go from something like this :
<TAG val="XXX">a hundred</TAG><TAG val="XXX">a thousand</TAG>

to something like this :
<TAG val="900">nine hundred</TAG><TAG val="1000">a thousand</TAG>

Instead I am getting something like this :
<TAG val="1000">nine hundred</TAG><TAG val="1000">a thousand</TAG>

The value which is used in the substitution is always the last match. Now, the puzzling thing is, I do this in other parts of my code and it seems to work. Is there a more reliable/safer way to do this, knowing that a global replace will not do and I am reading lines in a file one at a time. Each line has possibly multiple tags of the same type.

To give you an idea, what I'm doing is something like this :

$text = "<TAG val="XXX">a hundred</TAG><TAG val="XXX">a thousand</TAG>";
while ($text =~ m/val="XXX"/) {
$text = &replace($text);
print $text; # or whatever
}

sub replace {
if ($text =~ val="XXX">(.+)</TAG> {
$val = &convert($1);
$text =~ s/val="XXX"/val="$val"/;
}
}

&covert converts the value between tags to the desired format (ie from words to numerical format).


THANKS VERY MUCH for any comments/tips!
 
You maybe just need the "g" modifier on the end of the regexp:

Code:
while ($text =~ m/val="XXX"/[b]g[/b]) {
  $text = &replace($text);
  print $text; # or whatever
}

which means to find all occurances of a pattern.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Also, don't ever split up matching and substituting in such a way. Simply do it in a single step using the 'e' modifier to execute code in the substitution block.

Code:
[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]$text[/blue] = [red]qq{[/red][purple]<TAG val="XXX">a hundred</TAG><TAG val="XXX">a thousand</TAG>[/purple][red]}[/red][red];[/red]

[blue]$text[/blue] =~ [red]s{[/red][purple]<TAG val="XXX">([^<])</TAG>[/purple][red]}[/red][red]{[/red][purple][/purple]
[purple]	my ([blue]$words[/blue]) = ([blue]$1[/blue]);[/purple]
[purple]	my [blue]$num[/blue] = convert([blue]$words[/blue]);[/purple]
[purple]	qq{<TAG val="[blue]$num[/blue]">[blue]$words[/blue]</TAG>}[/purple]
[purple][/purple][red]}[/red][red]eg[/red][red];[/red]

- Miller
 
andreb7,
a problem with your code (besides some evident mistypings) is that the pattern [tt]/val="XXX">(.+)<\/TAG>/[/tt] will match from the first "XXX" to the last </TAG> and $1 will contain [tt]a hundred</TAG><TAG val="XXX">a thousand[/tt] (don't know however what your convert function does with this).
Try this one instead (and report the result together with some carefully written code if you need more help):
[tt]/val="XXX">(.+?)<\/TAG>/[/tt]
The addition of ? forces a match on the least possible length.
Also note that your patterns won't match with legal variations in HTML writing: just think of a space put in the many positions allowed for it, around an equal sign for example.

Franco
: Online tools for structural design
: Magnetic brakes for fun rides
: Air bearing pads
 
Hey, thanks Franco!
It was indeed a problem with greedy matching. I'll have to look out for that in the future. Now I get the desired output.

Miller, I'm not familiar with your method...it might work, but Franco's tip requires the fewest modifications to my code, so I'll go with it...I will test what you suggest though.

Kevin, the g modifier is not useful in this situation as I am trying to replace things in context only and the substituting value has to come from the local context in the string. That's why I use a loop instead.

Thanks a lot for your help guys.
 
andreb7,

I demonstrated one of the most basic usages of regular expressions. I suggest that you learn it.


The only thing that may be confusing you is the fact that I use the s{}{} delimiter instead of the standard s///. I did this simply because when dealing with html it is better to use a delimiter where you won't have to escape the forward slash of your end tags. And the preferred alternate delimiter is balanced braces.

- Miller
 
Miller

Thanks for the advice. I was not familiar with the syntax. In fact I wasn't aware of the search and replace capabilities using evaluation. But I can't get it to work. Here is a simplified example of your suggestion :

Code:
my $text = qq{<TAG val="XXX">100</TAG><TAG val="XXX">1000</TAG>};

$text =~ s{<TAG val="XXX">([^<])</TAG>}{
    qq{<TAG val="$1">$1</TAG>}
}eg;

print $text;

The input string is unchanged. Any ideas?
Cheers
 
I think Millers example needed a quantifier, add a '+' and it should work:

([^<]+)

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
As my coding brethren already pointed out, I simply forgot my repetition quantifier:

Code:
[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]$text[/blue] = [red]qq{[/red][purple]<TAG val="XXX">a hundred</TAG><TAG val="XXX">a thousand</TAG>[/purple][red]}[/red][red];[/red]

[blue]$text[/blue] =~ [red]s{[/red][purple]<TAG val="XXX">([^<]+)</TAG>[/purple][red]}[/red][red]{[/red][purple][/purple]
[purple]	my ([blue]$words[/blue]) = ([blue]$1[/blue]);[/purple]
[purple]	my [blue]$num[/blue] = convert([blue]$words[/blue]);[/purple]
[purple]	qq{<TAG val="[blue]$num[/blue]">[blue]$words[/blue]</TAG>}[/purple]
[purple][/purple][red]}[/red][red]eg[/red][red];[/red]

[url=http://perldoc.perl.org/functions/print.html][black][b]print[/b][/black][/url] [blue]$text[/blue][red];[/red]

[url=http://perldoc.perl.org/functions/sub.html][black][b]sub[/b][/black][/url] [maroon]convert[/maroon] [red]{[/red]
	[black][b]my[/b][/black] [red]([/red][blue]$words[/blue][red])[/red] = [blue]@_[/blue][red];[/red]
	[black][b]my[/b][/black] [blue]%static[/blue] = [red]([/red]
		[red]'[/red][purple]a hundred[/purple][red]'[/red] => [fuchsia]100[/fuchsia],
		[red]'[/red][purple]a thousand[/purple][red]'[/red] => [fuchsia]1000[/fuchsia],
	[red])[/red][red];[/red]
	[url=http://perldoc.perl.org/functions/return.html][black][b]return[/b][/black][/url] [blue]$static[/blue][red]{[/red][blue]$words[/blue][red]}[/red] or [url=http://perldoc.perl.org/functions/die.html][black][b]die[/b][/black][/url] [red]"[/red][purple]Unknown [blue]$words[/blue][/purple][red]"[/red][red];[/red]
[red]}[/red]

- Miller
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top