2013-05-14 1 views
1

Python traite \ uxxxx comme un caractère unicode qui s'échappe à l'intérieur d'un littéral de chaîne (par exemple, "u \ u2014" est interprété comme un caractère Unicode U + 2014). Mais je viens de découvrir (Python 2.7) que le module regex standard ne traite pas \ uxxxx comme un caractère Unicode. Exemple:Est-ce que python re (regex) a une alternative aux séquences d'échappement Unicode?

codepoint = 2014 # Say I got this dynamically from somewhere 

test = u"This string ends with \u2014" 
pattern = r"\u%s$" % codepoint 
assert(pattern[-5:] == "2014$") # Ends with an escape sequence for U+2014 
assert(re.search(pattern, test) != None) # Failure -- No match (bad) 
assert(re.search(pattern, "u2014")!= None) # Success -- This matches (bad) 

Il est évident que si vous êtes en mesure de préciser votre modèle de regex comme une chaîne littérale, alors vous pouvez avoir le même effet que si le moteur regex se comprend \ uxxxx échappe:

test = u"This string ends with \u2014" 
pattern = u"\u2014$" 
assert(pattern[:-1] == u"\u2014") # Ends with actual unicode char U+2014 
assert(re.search(pattern, test) != None) 

Mais Et si vous deviez construire votre modèle dynamiquement?

+1

Vous créez une chaîne ' '\ u% s' d'abord, puis en interpolant le codepoint, et cela est * not * interprété comme "\ u ...." en premier. C'est * comportement attendu *. Utilisez 'u '% s'% unichr (codepoint)' à la place. –

Répondre

1

Une possibilité est, plutôt que d'appeler des méthodes directement, les envelopper dans quelque chose qui peut comprendre que vous échappe en leur nom. Quelque chose comme ceci:

def my_re_search(pattern, s): 
    return re.search(unicode_unescape(pattern), s) 

def unicode_unescape(s): 
     """ 
     Turn \uxxxx escapes into actual unicode characters 
     """ 
     def unescape_one_match(matchObj): 
       escape_seq = matchObj.group(0) 
       return escape_seq.decode('unicode_escape') 
     return re.sub(r"\\u[0-9a-fA-F]{4}", unescape_one_match, s) 

Exemple de fonctionner:

pat = r"C:\\.*\u20ac" # U+20ac is the euro sign 
>>> print pat 
C:\\.*\u20ac 

path = ur"C:\reports\twenty\u20acplan.txt" 
>>> print path 
C:\reports\twenty€plan.txt 

# Underlying re.search method fails to find a match 
>>> re.search(pat, path) != None 
False 

# Vs this: 
>>> my_re_search(pat, path) != None 
True 

Merci à Process escape sequences in a string in Python pour souligner l'idée decode (le "unicode_escape").

Mais notez que vous ne pouvez pas lancer tout votre motif par décodage ("unicode_escape"). Cela fonctionnera de temps en temps (parce que la plupart des caractères spéciaux de regex ne changent pas leur signification quand vous mettez une barre oblique inversée à l'avant), mais cela ne fonctionnera pas en général. Par exemple, ici en utilisant decode ("unicode_escape") modifie le sens de l'expression rationnelle:

pat = r"C:\\.*\u20ac" # U+20ac is the euro sign 
>>> print pat 
C:\\.*\u20aC# Asks for a literal backslash 

pat_revised = pat.decode("unicode_escape") 
>>> print pat_revised 
C:\.*€ # Asks for a literal period (without a backslash) 
4

Utilisez le unichr() function pour créer des personnages unicode d'un point de code:

pattern = u"%s$" % unichr(codepoint) 
+0

Ceci est une bonne solution à mon exemple. Mais cela me fait aussi prendre conscience que mon exemple n'illustre pas ce que j'espérais réellement poser. Je me suis moins préoccupé de l'injection d'un seul point de code dans une chaîne de forme connue, et plus préoccupé par la façon de traiter un nombre indéterminé de \ u échappements dans une chaîne arbitraire. C'est la direction que j'essayais d'adopter avec ma propre réponse - même si j'aurais peut-être dû utiliser unichr dans ce cadre. – Chris

+0

@Chris: J'ai couvert les échappements ** juste ** '\ uxxxx' en utilisant une expression régulière dans [cette réponse précédente] (http://stackoverflow.com/questions/14367369/unescape-unicode-escapes-but-not- carriage-returns-et-line-feeds-in-python/14367455 # 14367455). –

+0

Que signifie le "% s $" '? – alvas