CraigP
CraigP

Reputation: 453

Perl Simple Regexp

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

Answers (3)

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89557

You can use this:

^(?>[^ ]++| (?!xyz))+ (?:xyz)?tip$

Upvotes: 0

Tim Peoples
Tim Peoples

Reputation: 354

What you need is a "zero width positive look-ahead assertion"... so, your regex would look something like:

\S+\s(?:xyz)?(?=tip)

Regular expression visualization

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

Andrew Clark
Andrew Clark

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

Related Questions