3

我正在尝试制作一个匹配如下内容的正则表达式:

[[uid::page name|page alias]]

例如:

[[nw::Home|Home page]]

uid 和页面别名都是可选的。

我想允许分隔符::|仅出现一次,并且仅按显示的顺序出现。但是,:应该允许在 uid 之后的任何位置使用该字符。问题就在这里。

以下正则表达式工作得很好,除了它匹配::出现两次或出现在错误位置的字符串:

regex = r'\[\[([\w]+::)?([^|\t\n\r\f\v]+)(\|[^|\t\n\r\f\v]+)?\]\]'
re.match(regex, '[[Home]]') # matches, good
re.match(regex, '[[Home|Home page]]') # matches, good
re.match(regex, '[[nw::Home]]') # matches, good
re.match(regex, '[[nw::Home|Home page]]') # matches, good
re.match(regex, '[[nw|Home|Home page]]') # doesn't match, good
re.match(regex, '[[nw|Home::Home page]]') # matches, bad
re.match(regex, '[[nw::Home::Home page]]') # matches, bad

我已经阅读了所有关于负前瞻和后瞻表达式的信息,但我不知道如何在这种情况下应用它们。任何建议,将不胜感激。

编辑:我还想知道如何防止分隔符包含在匹配结果中,如下所示:

('nw::', 'Home', '|Home page')

4

3 回答 3

4

如果我正确理解您的需求,您可以使用:

\[\[(?:(?<uid>\w+)::)?(?!.*::)(?<page>[^|\t\n\r\f\v]+)(?:\|(?<alias>[^|\t\n\r\f\v]+))?\]\]
                      ^^^^^^^^

请参阅此处进行演示。uid我在捕获后添加了一个负前瞻。

我已经为捕获的组命名,但如果您不想要它们,那就是没有命名捕获组的名称:

\[\[(?:(\w+)::)?(?!.*::)([^|\t\n\r\f\v]+)(?:\|([^|\t\n\r\f\v]+))?\]\]
于 2013-07-04T15:46:29.043 回答
0

那么,你怎么看这个:

import re

regex = r'''
    \[\[                            # opening [[
        ([\w ]+)                    # first word (with possible spaces)
        (?:
            ::                      # the two colons
            (                       # second word (with possible spaces and single colons)
                [\w ]+              # word characters and spaces
                (?:
                    :               # a colon
                    [\w ]+          # word characters and spaces
                )*                  # not required, but can repeat unlimitted
            )
        )?                          # not required
        (?:
            \|                      # a pipe
            ([\w ]+)                # thid word (with possible spaces)
        )?
    \]\]                            # closing ]]
'''

test_strings = (
    '[[Home]]',
    '[[Home|Home page]]',
    '[[nw::Home]]',
    '[[nw::Home|Home page]]',
    '[[nw|Home|Home page]]',
    '[[nw|Home::Home page]]',
    '[[nw::Home::Home page]]',
    '[[nw::Home:Home page]]',
    '[[nw::Home:Home page|Home page]]'
)

for test_string in test_strings:
    print re.findall(regex, test_string, re.X)

输出:

[('Home', '', '')]
[('Home', '', 'Home page')]
[('nw', 'Home', '')]
[('nw', 'Home', 'Home page')]
[]
[]
[]
[('nw', 'Home:Home page', '')]

它不使用前瞻/后视。它确实允许字符串中第一个冒号之后的单个冒号::(如最后两个测试字符串所示)。正则表达式的简短版本是:

\[\[([\w ]+)(?:::([\w ]+(?::[\w ]+)*))?(?:\|([\w ]+))?\]\]

唯一的问题是您必须检查第二个匹配项是否为空,如果是,则没有双冒号(::),您应该使用第一个匹配项,通常是冒号之前的字符串。

于 2013-07-04T16:10:09.817 回答
0

这行得通吗??- http://ideone.com/NeIouP

import re
regex = r'\[\[(([\w]+)::)?([^|\t\n\r\f\v]+)(\|([^\t\n\r\f\v]+))?\]\]'
print re.match(regex, '[[Home]]').group(2,3,5) # matches, good
print re.match(regex, '[[Home|Home page]]').group(2,3,5) # matches, good
print re.match(regex, '[[nw::Home]]').group(2,3,5) # matches, good
print re.match(regex, '[[nw::Home|Home page]]').group(2,3,5) # matches, good
print re.match(regex, '[[nw|Home|Home page]]').group(2,3,5) # doesn't match, good
print re.match(regex, '[[nw|Home::Home page]]').group(2,3,5) # matches, bad
print re.match(regex, '[[nw::Home::Home page]]').group(2,3,5) # matches, bad
于 2013-07-04T16:20:27.313 回答