2010-09-08 6 views
1

pour mon application CGI J'écris une fonction pour obtenir la langue préférée du navigateur (fournie dans la variable HTTP_ACCEPT_LANGUAGE). Je veux trouver toutes les étiquettes de langue dans cette variable avec des expressions régulières (Le modèle général d'une étiquette de langue est défini dans RFC1766). EBNF de RFC1766 ('1 * 8ALPHA' signifie un à huit caractères ASCII):Expressions régulières Python - Correspondance complète

Language-Tag = Primary-tag *("-" Subtag) 
Primary-tag = 1*8ALPHA 
Subtag = 1*8ALPHA 

j'ai écrit cette expression régulière pour une étiquette de langue:

(([a-z]{1,8})(-[a-z]{1,8})*) 

Si j'utilise cette expression, module re de Python fournit les éléments suivants

>>import re 

>>re.findall("(([a-z]{1,8})(-[a-z]{1,8})*)", "x-pig-latin en-us de-de en", re.IGNORECASE) 
[('x-pig-latin', 'x', '-latin'), ('en-us', 'en', '-us'), ('de-de', 'de', '-de'), ('en', 'en', '')] 

Le résultat est correct. Mais je n'ai besoin que de matches complets comme 'de-de' ou 'x-pig-latin'. Puis-je supposer que le premier match d'un groupe est toujours le plus complet? Ou y a-t-il un drapeau indiquant les matchs les plus complets?

Stefan

Répondre

0

Je ne sais pas si vous avez déjà vérifié, mais this article a beaucoup de bons pointeurs au sujet de faire Accept-Language l'analyse syntaxique, ainsi que d'une référence à une bibliothèque qui a déjà résolu le problème. En ce qui concerne la question re, Doug Hellman a un great breakdown of re dans son récent module Python de la semaine.

4

Vous pouvez utiliser le: opérateur pour empêcher le moteur de regex de sauver des sous-modèles bracketing:

((?:[a-z]{1,8})(?:-[a-z]{1,8})*) 

Cela donne la sortie:

re.findall("((?:[a-z]{1,8})(?:-[a-z]{1,8})*)", "x-pig-latin en-us de-de en", re.IGNORECASE) 
['x-pig-latin', 'en-us', 'de-de', 'en'] 

Pour répondre à votre question, le premier match retourné par findall devrait être la sous-chaîne correspondante complète.

+0

Merci, c'est exactement ce que je recherche. Je n'ai jamais utilisé l'opérateur?: Avant. – Stefan

2

Faites vos groupes internes (c.-à-parenthèses) dans non ceux -capturing: c'est le changement de:

(([a-z]{1,8})(-[a-z]{1,8})*) 

à:

((?:[a-z]{1,8})(?:-[a-z]{1,8})*) 

Pour résumer, la notation de motif (?: ...) définit un groupe non -capturing: les parenthèses servent à contrôler la priorité, mais ne laissent pas de traces dans les objets .groups() et autres traits liés au groupe de capture.

Les parenthèses simples, (...), signifient un capturant le groupe.

Il n'y a aucune raison d'utiliser des groupes de capture pour les sous-correspondances que vous êtes explicitement intéressés par, bien entendu, les et non. Utilisez-les seulement pour les sous-correspondances que vous voulez faire! -)