Reputation: 3
How do I match for only one instance of a word in a string? As an example, with "fred" as my test word, match should be TRUE for the string "fredwilmawilliamjohn" but should be FALSE for "fredwilmawilliamfred"?
Upvotes: 0
Views: 832
Reputation: 98508
/fred(*COMMIT)(?!.*?fred)/s
(*COMMIT)
(added in perl 5.10) says after matching fred
, don't backtrack and try matching it again if the remainder of the regex fails. The rest of the regex says don't match if .*?fred
(any number of any characters followed by fred) matches at that point, after the first fred, i.e. there is no further fred.
Before 5.10, you would need to force the first fred in the regex to only match the first fred in the string like so:
/^(?:(?!fred).)*+fred(?!.*?fred)/s
(match any number of characters so long as they aren't the beginning of fred before matching the fred that cannot then be followed by another fred).
Or
/^(?>.*?fred)(?!.*?fred)/s
(start at the beginning of the string and, without allowing backtracking, find the first fred, and assert that there is not a fred after it)
(Throughout, /s is used to make .
match any character, not just any non-newline character.)
Upvotes: 1
Reputation: 226
It sounds like you want to match the pattern and verify that it doesn't occur subsequently in the string. How about this, using negative lookahead
m/fred(?!.*fred)/
Breaking it down:
?! -- not followed by
.* -- zero or more characters
Upvotes: 0
Reputation: 54381
You can count the number of matches by using the /g
flag in list context, and converting that into scalar context.
use strict;
use warnings;
use feature 'say';
for my $string (qw(fredwilmawilliamjohn fredwilmawilliamfred) ) {
my $count = () = $string =~ m/(fred)/g;
if ( $count == 1 ) {
say $string;
}
}
The most relevant part is the = () =
, which forces the match into list context. The my $count
will then force that list of matches into scalar context, which gives you the number of items in the list. That's your number of matches.
Upvotes: 2