Regular expressions in python to match Twitter handles
Question: I'm trying to use regular expressions to capture all Twitter handles within a
tweet body. The challenge is that I'm trying to get handles that

  1. Contain a specific string
  2. Are of unknown length
  3. May be followed by either 
     * punctuation
     * whitespace
     * or the end of string.

For example, for each of these strings, Ive marked _in italics_ what I'd like
to return.

> "@handle what is your problem?" _[RETURN '@handle']_
>
> "what is your problem @handle?" _[RETURN '@handle']_
>
> "@123handle what is your problem @handle123?" _[RETURN '@123handle',
> '@handle123']_

This is what I have so far:

    
    
    >>> import re
    >>> re.findall(r'(@.*handle.*?)\W','hi @123handle, hello @handle123')
    ['@123handle']
    # This misses the handles that are followed by end-of-string
    

I tried modifying to include an `or` character allowing the end-of-string
character. Instead, it just returns the whole string.

    
    
    >>> re.findall(r'(@.*handle.*?)(?=\W|$)','hi @123handle, hello @handle123')
    ['@123handle, hello @handle123']
    # This looks like it is too greedy and ends up returning too much
    

How can I write an expression that will satisfy both conditions?

I've looked at a [couple](http://stackoverflow.com/questions/16932012/regex-
how-to-match-any-string-until-whitespace-or-until-punctuation-followed-b)
[other](http://stackoverflow.com/questions/6713310/how-to-specify-space-or-
end-of-string-and-space-or-start-of-string) places, but am still stuck.


Answer: It seems you are trying to match strings starting with `@`, then having 0+
word chars, then `handle`, and then again 0+ word chars.

Use

    
    
    r'@\w*handle\w*'
    

or - to avoid matching `@`+word chars in emails:

    
    
    r'\B@\w*handle\w*'
    

See the [Regex 1 demo](https://regex101.com/r/jW4xL1/1) and the [Regex 2
demo](https://regex101.com/r/jW4xL1/2) (the `\B` non-word boundary requires a
non-word char or start of string to be right before the `@`).

Note that the `.*` is a greedy dot matching pattern that matches any
characters other than newline, as many as possible. `\w*` only matches 0+
characters (also as many as possible) but from the `[a-zA-Z0-9_]` set if the
`re.UNICODE` flag is not used (and it is not used in your code).

[Python demo](http://ideone.com/T1bZx4):

    
    
    import re
    p = re.compile(r'@\w*handle\w*')
    test_str = "@handle what is your problem?\nwhat is your problem @handle?\n@123handle what is your problem @handle123?\n"
    print(p.findall(test_str))
    # => ['@handle', '@handle', '@123handle', '@handle123']
    

