How to match the first word after an expression with regex?

85,126

Solution 1

This sounds like a job for lookbehinds, though you should be aware that not all regex flavors support them. In your example:

(?<=\bipsum\s)(\w+)

This will match any sequence of letter characters which follows "ipsum" as a whole word followed by a space. It does not match "ipsum" itself, you don't need to worry about reinserting it in the case of, e.g. replacements.

As I said, though, some flavors (JavaScript, for example) don't support lookbehind at all. Many others (most, in fact) only support "fixed width" lookbehinds — so you could use this example but not any of the repetition operators. (In other words, (?<=\b\w+\s+)(\w+) wouldn't work.)

Solution 2

Some of the other responders have suggested using a regex that doesn't depend on lookbehinds, but I think a complete, working example is needed to get the point across. The idea is that you match the whole sequence ("ipsum" plus the next word) in the normal way, then use a capturing group to isolate the part that interests you. For example:

String s = "Lorem ipsum dolor sit amet, consectetur " +
    "adipiscing elit. Nunc eu tellus vel nunc pretium " +
    "lacinia. Proin sed lorem. Cras sed ipsum. Nunc " +
    "a libero quis risus sollicitudin imperdiet.";

Pattern p = Pattern.compile("ipsum\\W+(\\w+)");
Matcher m = p.matcher(s);
while (m.find())
{
  System.out.println(m.group(1));
}

Note that this prints both "dolor" and "Nunc". To do that with the lookbehind version, you would have to do something hackish like:

Pattern p = Pattern.compile("(?<=ipsum\\W{1,2})(\\w+)");

That's in Java, which requires the lookbehind to have an obvious maximum length. Some flavors don't have even that much flexibility, and of course, some don't support lookbehinds at all.

However, the biggest problem people seem to be having in their examples is not with lookbehinds, but with word boundaries. Both David Kemp and ck seem to expect \b to match the space character following the 'm', but it doesn't; it matches the position (or boundary) between the 'm' and the space.

It's a common mistake, one I've even seen repeated in a few books and tutorials, but the word-boundary construct, \b, never matches any characters. It's a zero-width assertion, like lookarounds and anchors (^, $, \z, etc.), and what it matches is a position that is either preceded by a word character and not followed by one, or followed by a word character and not preceded by one.

Solution 3

ipsum\b(\w*)

Solution 4

With javascript you can use (?=ipsum.*?(\w+))

This will get the second occurrence as well (Nunc)

Share:
85,126

Related videos on Youtube

Matthew Taylor
Author by

Matthew Taylor

OS Community Flag-Bearer for NuPIC.

Updated on July 09, 2022

Comments

  • Matthew Taylor
    Matthew Taylor almost 2 years

    For example, in this text:

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc eu tellus vel nunc pretium lacinia. Proin sed lorem. Cras sed ipsum. Nunc a libero quis risus sollicitudin imperdiet.

    I want to match the word after 'ipsum'.

  • Lordn__n
    Lordn__n about 15 years
    That'll match the rest of the sentence.
  • tliff
    tliff about 15 years
    you have to make that ungreedy
  • Lordn__n
    Lordn__n about 15 years
    Actually it's not implementation dependent, or at least I've never come across a regex implementation that is non-greedy by default. Non-greedy is always a switch (at least in Perl, PHP, Java and .Net).
  • Matthew Taylor
    Matthew Taylor about 15 years
    That seems to only match ipsum.
  • Lordn__n
    Lordn__n about 15 years
    I'd probably make that \b+(\w+) at least
  • Matthew Taylor
    Matthew Taylor about 15 years
    ipsum\b+(\w+) is not valid regex.
  • Ates Goral
    Ates Goral about 15 years
    @Matthew Taylor: It depends on your platform. You didn't specify which platform/language you're using.
  • cjk
    cjk about 15 years
    @cletus: regex implementation can by definition include passing switches to the call to the regex function
  • Lordn__n
    Lordn__n about 15 years
    Lookbehinds tend to be pretty limited when it comes to using wildcards though.
  • Lordn__n
    Lordn__n about 15 years
    Yes but they all default to greedy and you pass in switches to turn that off (although PHP has a switch to invert the behaviour of *? and +? to being greedy while * and + become non-greedy). Still, that's a switch from the default.
  • Matthew Taylor
    Matthew Taylor about 15 years
    I see. I'm using Java regex on OS X.
  • Alan Moore
    Alan Moore about 15 years
    \b+ matches one or more word boundaries, which makes no sense because a word boundary has zero length. Some flavors will ignore the + but others will reject it as an error. I think "ipsum\s+(\w+)" is what you're groping for.
  • Alan Moore
    Alan Moore about 15 years
    Even if you make it non-greedy--ie, "ipsum\b(.*?)\b"--it still won't work. The "(.*?)" will just match the space between 'ipsum' and the next word.
  • user55400
    user55400 about 15 years
    Lookbehinds might not even be necessary here. Depending on what 'I want to match' in the question refers to, see David Kemp's solution.
  • annakata
    annakata about 15 years
    zero-width tends to be what you want though, it's just that grouping is a trivial get out of jail card.
  • Peter Boughton
    Peter Boughton about 15 years
    Fixed width is a misleading term - it is more "max width", yes? In most cases it is possible to use a suitable limit, for example: (?<=\b\w{1,100}\s{1,100})
  • Ben Blank
    Ben Blank about 15 years
    @Peter — No, it really is fixed width. Try your regex there in Python; it throws an exception.
  • JonM
    JonM over 10 years
    I think I have discovered a way to circumvent the fixed width lookbehind restriction in some flavours of regex in some cases. Say you want to find B but only if it isn't preceded by A and any number of spaces. In most flavours of regex you wouldn't be able to use (?<!A *)(B) since the lookbehind isn't fixed. Instead you could use ^(?>(?>(?>(?>(?!A *B).)*)A *B)*).*?(B) Note that this can get very inefficient if the flavour does not also support atomic grouping or possessive quantifiers...