3

これは、いくつかの文字列で URL を検索するための正規表現です (以降のアクションはドメインに基づいているため、ドメインのグループが必要です)。この例では、いくつかの文字列 'ffffffffff' が非常に遅いことに気付きました。

>>> URL_ALLOWED = r"[a-z0-9$-_.+!*'(),%]"
>>> URL_RE = re.compile(
...     r'(?:(?:https?|ftp):\/\/)?'  # protocol
...     r'(?:www.)?' # www
...     r'('  # host - start
...         r'(?:'
...             r'[a-z0-9]'  # first character of domain('-' not allowed)
...             r'(?:'
...                 r'[a-z0-0-]*'  #  characters in the middle of domain
...                 r'[a-z0-9]' #  last character of domain('-' not allowed)
...             r')*'
...             r'\.'  # dot before next part of domain name
...         r')+'
...         r'[a-z]{2,10}'  # TLD
...         r'|'  # OR
...         r'(?:[0-9]{1,3}\.){3}[0-9]{1,3}'  # IP address
...     r')' # host - end
...     r'(?::[0-9]+)?'  # port
...     r'(?:\/%(allowed_chars)s+/?)*'  # path
...     r'(?:\?(?:%(allowed_chars)s+=%(allowed_chars)s+&)*'  # GET params
...     r'%(allowed_chars)s+=%(allowed_chars)s+)?'  # last GET param
...     r'(?:#[^\s]*)?' % {  # anchor
...         'allowed_chars': URL_ALLOWED
...     },
...     re.IGNORECASE
... )
>>> from time import time
>>> strings = [
...     'foo bar baz',
...     'blah blah blah blah blah blah',
...     'f' * 10,
...     'f' * 20,
...     'f' * 30,
...     'f' * 40,
... ]
>>> def t():
...     for string in strings:
...             t1 = time()
...             URL_RE.findall(string)
...             print string, time() - t1
... 
>>> t()
foo bar baz 3.91006469727e-05
blah blah blah blah blah blah 6.98566436768e-05
ffffffffff 0.000313997268677
ffffffffffffffffffff 0.183916091919
ffffffffffffffffffffffffffffff 178.445468903

ええ、非常に単純な正規表現 (たとえば、ドットを含む単語) を使用し、後で urlparse を使用してドメインを取得する別の解決策があることは知っていますが、URL にプロトコルがない場合、urlparse は期待どおりに機能しません。

>>> urlparse('example.com')
ParseResult(scheme='', netloc='', path='example.com', params='', query='', fragment='')
>>> urlparse('http://example.com')
ParseResult(scheme='http', netloc='example.com', path='', params='', query='', fragment='')
>>> urlparse('example.com/test/test')
ParseResult(scheme='', netloc='', path='example.com/test/test', params='', query='', fragment='')
>>> urlparse('http://example.com/test/test')
ParseResult(scheme='http', netloc='example.com', path='/test/test', params='', query='', fragment='')
>>> urlparse('example.com:1234/test/test')
ParseResult(scheme='example.com', netloc='', path='1234/test/test', params='', query='', fragment='')
>>> urlparse('http://example.com:1234/test/test')
ParseResult(scheme='http', netloc='example.com:1234', path='/test/test', params='', query='', fragment='')

はい、先頭に http:// を追加することも解決策です (他に urlparse の問題がないかどうかはまだ 100% 確信が持てません) が、とにかくこの正規表現の何が問題なのか知りたいです

4

2 に答える 2

3

この部分が原因だと思います

...         r'(?:'
...             r'[a-z0-9]'  # first character of domain('-' not allowed)
...             r'(?:'
...                 r'[a-z0-0-]*'  #  characters in the middle of domain
...                 r'[a-z0-9]' #  last character of domain('-' not allowed)
...             r')*'
...             r'\.'  # dot before next part of domain name
...         r')+'

set_of_symbols#1 と set_of_symbols#2 が同じシンボルを持つ場合、このような構造 ([set_of_symbols#1]*[set_of_symbols#2])* を使用しないでください。

次のコードを使用してみてください。

...         r'(?:'
...             r'[a-z0-9]'  # first character of domain('-' not allowed)
...             r'[a-z0-0-]*'  #  characters in the middle of domain
...             r'(?<=[a-z0-9])' #  last character of domain('-' not allowed)
...             r'\.'  # dot before next part of domain name
...         r')+'

うまくいくはずです。

于 2012-08-17T14:59:12.097 に答える
0

参考までに、 re.VERBOSE フラグを使用してこれを読みやすくすることもできます

 URL_RE = re.compile(r"""
    (?:(?:https?|ftp):\/\/)?                            # protocol
    (?:www.)?                                           # www
    (                                                   # host - start
        (?:
            [a-z0-9]                                    # first character of domain('-' not allowed)
            (?:
                [a-z0-0-]*                              #  characters in the middle of domain
                [a-z0-9]                                #  last character of domain('-' not allowed)
            )*
            \.                                          # dot before next part of domain name
        )+
        [a-z]{2,10}                                     # TLD
        |                                               # OR
        (?:[0-9]{1,3}\.){3}[0-9]{1,3}                   # IP address
    )                                                   # host - end
    (?::[0-9]+)?                                        # port
    (?:\/%(allowed_chars)s+/?)*                         # path
    (?:\?(?:%(allowed_chars)s+=%(allowed_chars)s+&)*    # GET params
    %(allowed_chars)s+=%(allowed_chars)s+)?             # last GET param
    (?:#[^\s]*)?
""" % {  # anchor
         'allowed_chars': URL_ALLOWED
     },
     re.IGNORECASE|re.VERBOSE
 )
于 2012-08-17T16:01:11.073 に答える