Reputation: 453
I have a valid string, somestr xyztip
, where xyz
is optional. But if xyz
does exist, it needs to be next to tip
(no whitespace).
So valid strings are: somestr tip
or somestr xyztip
.
An invalid string would be: somestr xyz tip
(space between xyz
and tip
)
I've tried many combinations, but I can't get the regexp to balk at a space between 'xyz' & 'tip'. The one below is what I would think should work:
/^.+?\s(xyz)?tip$/
The problem is the syntax before the '(xyz)?' - that is the '.+?\s' . This is saying any char 1 or more times, not greedy followed by a single whitespace.
what am I missing here?
Upvotes: 0
Views: 71
Reputation: 89557
You can use this:
^(?>[^ ]++| (?!xyz))+ (?:xyz)?tip$
Upvotes: 0
Reputation: 354
What you need is a "zero width positive look-ahead assertion"... so, your regex would look something like:
\S+\s(?:xyz)?(?=tip)
From perldoc perlre
:
"(?=pattern)"
A zero-width positive look-ahead assertion. For example, "/\w+(?=\t)/"
matches a word followed by a tab, without including the tab in $&.
Upvotes: 0
Reputation: 208475
Assuming that xyz
cannot be anywhere in the string except for immediately before tip
, the following should work:
/^((?!xyz).)+\s(xyz)?tip$/
This changes the .+?
to ((?!xyz).)+
. By putting the negative lookahead within the repeating group we can match any number of characters but stop if we encounter xyz
, so ((?!xyz).)+
would match "foo" from "fooxyz". This allows us to make sure that xyz
is never matched by the first part of the regex, so that if it exists it has to be in the (xyz)?tip
portion of the regex.
Upvotes: 1