33

I have a string from which i want to extract 3 groups:

'19 janvier 2012' -> '19', 'janvier', '2012'

Month name could contain non ASCII characters, so [A-Za-z] does not work for me:

>>> import re
>>> re.search(ur'(\d{,2}) ([A-Za-z]+) (\d{4})', u'20 janvier 2012', re.UNICODE).groups()
(u'20', u'janvier', u'2012')
>>> re.search(ur'(\d{,2}) ([A-Za-z]+) (\d{4})', u'20 février 2012', re.UNICODE).groups()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'
>>> 

I could use \w but it matches digits and underscore:

>>> re.search(ur'(\w+)', u'février', re.UNICODE).groups()
(u'f\xe9vrier',)
>>> re.search(ur'(\w+)', u'fé_q23vrier', re.UNICODE).groups()
(u'f\xe9_q23vrier',)
>>> 

I tried to use [:alpha:], but it's not working:

>>> re.search(ur'[:alpha:]+', u'février', re.UNICODE).groups()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'
>>> 

If i could somehow match \w without [_0-9], but i don't know how. And even if i find out how to do this, is there a ready shortcut like [:alpha:] which works in Python?

tchrist
  • 78,834
  • 30
  • 123
  • 180
warvariuc
  • 57,116
  • 41
  • 173
  • 227
  • 1
    As for `[:alpha:]`, this only works inside a character class, so the correct regex would be `[[:alpha:]]+`, but Python doesn't support these anyway. – Tim Pietzcker Jan 19 '12 at 09:58
  • Why not simply call .split() on the string? – yak Jan 19 '12 at 10:10
  • fyi `\w` already matches unicode see `For Unicode (str) patterns: Matches Unicode word characters; this includes most characters that can be part of a word in any language, as well as numbers and the underscore. If the ASCII flag is used, only [a-zA-Z0-9_] is matched.` ref https://docs.python.org/3/library/re.html though idk if we need the `re.UNICODE` flag. – Charlie Parker Jun 30 '22 at 19:43
  • do we really need the `re.UNICODE` flag? The docs seem to imply it already works for unicode: `Both patterns and strings to be searched can be Unicode strings (str) as well as 8-bit strings (bytes).` correct me if I am wrong. Ref: https://docs.python.org/3/library/re.html – Charlie Parker Jun 30 '22 at 19:44
  • @CharlieParker probably this question was asked during Python 2 era. – warvariuc Jul 07 '22 at 14:16

1 Answers1

64

You can construct a new character class:

[^\W\d_]

instead of \w. Translated into English, it means "Any character that is not a non-alphanumeric character ([^\W] is the same as \w), but that is also not a digit and not an underscore".

Therefore, it will only allow Unicode letters.

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • 2
    I already recognized that `\p{L}` is not supported, so your solution is the way to go +1. – stema Jan 19 '12 at 09:57
  • to include ``-`` in any regex character class, just put it at end (or beginning): ``[^\W\d_-]`` for this example. – RichVel Sep 18 '13 at 15:18
  • 3
    @RichVel: That will *forbid* a minus sign. – Tim Pietzcker Sep 18 '13 at 15:21
  • 2
    @TimPietzcker - Yes, I didn't read that comment well enough... one solution is to use regex alternation, e.g. something like this (not tested): ``([^\W\d_]|-)`` – RichVel Sep 19 '13 at 13:16
  • do we really need the `re.UNICODE` flag? The docs seem to imply it already works for unicode: `Both patterns and strings to be searched can be Unicode strings (str) as well as 8-bit strings (bytes).` correct me if I am wrong. Ref: https://docs.python.org/3/library/re.html – Charlie Parker Jun 30 '22 at 19:44
  • You're right, in Python 3 it's redundant. 2012, when this answer was written, Python 2 was still dominant, but I guess an edit is in order now :) – Tim Pietzcker Jul 02 '22 at 08:41