tags:

views:

47

answers:

3

Hello,

for my CGI application I'm writing a function to get the browser's preferred language (supplied in the HTTP_ACCEPT_LANGUAGE variable). I want to find all language tags in this variable with regular expressions (The general pattern of a language tag is defined in RFC1766). EBNF from RFC1766 ('1*8ALPHA' means one to eight ASCII chars):

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

I wrote this regular expression for a language tag:

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

If i use this expression, Python's re module supplies the following

>>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', '')]

The result is correct. But I only need complete matches like 'de-de' or 'x-pig-latin'. Can I assume that the first match of a group is always the most complete one? Or is there a flag telling re to show the most complete matches?

Stefan

A: 

Not sure if you've already checked it out, but this article has lots of good pointers about doing Accept-Language parsing, along with a reference to a library that has already solved the problem.

As far as your re question goes, Doug Hellman has a great breakdown of re in his recent Python Module of the Week.

Hank Gay
+3  A: 

You can use the ?: operator to prevent the regex engine from saving bracketed subpatterns:

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

This gives the output:

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']

To answer your question, the first match returned by findall should be the full matching substring.

GWW
Thanks, that's exactly I'm looking for. I never used the ?: operator before.
Stefan
+1  A: 

Make your inner groups (i.e., parentheses) into non-capturing ones: that is, change from:

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

to:

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

To recap, the pattern notation (?: ... ) defines a non-capturing group: the parentheses stills serve the purpose of controlling priority, but don't leave traces in the match object's .groups() and other capturing-group related traits.

Plain parentheses, ( ... ), mean a capturing group.

There is no reason to use capturing groups for sub-matches that you're explicitly not interested about, of course. Use them only for the sub-matches you do care about!-)

Alex Martelli