BBS水木清华站∶精华区
发信人: starw (化缘道人), 信区: Linux
标 题: Python Regular Expression HOWTO 4.3
发信站: BBS 水木清华站 (Tue Nov 21 23:45:46 2000)
嘿嘿,就一部分....看了半天才弄明白
4.3 Non-capturing, and Named Groups
Elaborate REs may use many groups, both to capture substrings of interest,
and to group and structure the RE itself. In complex REs, it becomes
difficult to keep track of the group numbers. There are two features which
help with this problem. Both of them use a common syntax for regular
expression extensions, so we'll look at that first.
Perl 5 added several additional features to standard regular expressions,
and the Python re module supports most of them. It would have been difficult
to choose new single-keystroke metacharacters or new special sequences
beginning with "\" to represent the new features, without making Perl's
regular expressions confusingly different from standard REs. If you chose
"&" as a new metacharacter, for example, old expressions would be assuming
that "&" was a regular character and wouldn't have escaped it by writing \&
or [&]. The solution chosen was to use (?...) as the extension syntax. "?"
immediately after a parenthesis was a syntax error, because the "?" would
have nothing to repeat, so this doesn't introduce any compatibility problems.
The characters immediately after the "?" indicate what extension is being
used, so (?=foo) is one thing (a positive lookahead assertion) and (?:foo)
is something else (a non-capturing group containing the subexpression foo).
Python adds an extension syntax to Perl's extension syntax. If the first
character after the question mark is a "P", you know that it's a extension
that's specific to Python. Currently there are two such extensions:
(?P<name>...) defines a named group, and (?P=name) is a backreference to a
named group. If future versions of Perl 5 add similar features using a
different syntax, the re module will be changed to support the new syntax,
while preserving the Python-specific syntax for compatibility's sake.
Now that we've looked at the general extension syntax, we can return to the
features that simplify working with groups in complex REs. Since groups are
numbered from left to right, and a complex expression may use many groups,
it can become difficult to keep track of the correct numbering, and modifying
such a complex RE is annoying. Insert a new group near the beginning, and you
change the numbers of everything that follows it.
First, sometimes you'll want to use a group to collect a part of a regular
expression, but aren't interested in retrieving the group's contents. You can
make this fact explicit by using a non-capturing group: (?:...), where you
can put any other regular expression inside the parentheses.
>>> m = re.match("([abc])+'', "abc")
>>> m.groups()
('c',)
>>> m = re.match("(?:[abc])+", "abc")
>>> m.groups()
()
Except for the fact that you can't retrieve the contents of what the group
matched, a non-capturing group behaves exactly the same as a capturing group;
you can put anything inside it, repeat it with a repetition metacharacter
such as "*", and nest it within other groups (capturing or non-capturing).
(?:...) is particularly useful when modifying an existing group, since you
can add new groups without changing how all the other groups are numbered.
It should be mentioned that there's no performance difference in searching
between capturing and non-capturing groups; neither form is any faster than
the other.
The second, and more significant, feature, is named groups; instead of
referring to them by numbers, groups can be referenced by a name.
The syntax for a named group is one of the Python-specific extensions:
(?P<name>...). name is, obviously, the name of the group. Except for
associating a name with a group, named groups also behave identically to
capturing groups. The MatchObject methods that deal with capturing groups
all accept either integers, to refer to groups by number, or a string
containing the group name. Named groups are still given numbers, so you
can retrieve information about a group in two ways:
>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'
>>> m.group(1)
'Lots'
Named groups are handy because they let you use easily-remembered names,
instead of having to remember numbers. Here's an example RE from the imaplib
module:
InternalDate = re.compile(r'INTERNALDATE "'
r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-'
r'(?P<year>[0-9][0-9][0-9][0-9])'
r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
r'"')
It's obviously much easier to retrieve m.group('zonem'), instead of having
to remember to retrieve group 9. Since the syntax for backreferences refers
to the number of the group, in an expression like (...)\1, there's naturally
a variant that uses the group name instead of the number. This is also a
Python extension: (?P=name) indicates that the contents of the group called
name should again be found at the current point. The regular expression for
finding doubled words, (\b\w+)\s+\1 can also be written as
(?P<word>\b\w+)\s+(?P=word):
>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
>>> p.search('Paris in the the spring').group()
'the the'
--
铜铁投洪冶,蝼蚁上粉墙。
阴阳无二义,天地我中央。
※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.117.27.35]
BBS水木清华站∶精华区