V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
xixitalk
V2EX  ›  Python

[请教]文本里多个 URL 处理

  •  
  •   xixitalk · 2016-10-01 06:50:18 +08:00 · 3221 次点击
    这是一个创建于 3007 天前的主题,其中的信息可能已经有所发展或是发生改变。
    文本要在浏览器显示,把 URL 都转换成了 HTML 超级链接。文本里可能出现多个 URL 网址。

    目前流程处理流程是:
    1 、正则表达式提取 URl 的 list
    2 、遍历 list 进行 replace 替换。比如: g.cn 替换成<a href="g.cn">g.cn</a>

    现在遇到这样的问题:
    如果一个 URL 包含另一个 URL ,替换就出现错乱。 replace 短 URL 会把长的 URL 替换搞乱。

    这个应该用什么流程来处理比较合适。
    22 条回复    2016-10-01 16:51:19 +08:00
    msg7086
        1
    msg7086  
       2016-10-01 07:04:11 +08:00
    举个栗子?
    imn1
        2
    imn1  
       2016-10-01 07:32:31 +08:00
    先把文本格式写出来才能讨论
    lxy42
        3
    lxy42  
       2016-10-01 07:59:52 +08:00 via Android
    正则表达式兼容 URL 中包含参数的情况
    xiaojj
        4
    xiaojj  
       2016-10-01 08:07:07 +08:00
    按你匹配的结果按顺序一个一个替换,不要一次性把文本里面的 g.cn 都替换成链接的 html
    xixitalk
        6
    xixitalk  
    OP
       2016-10-01 09:41:36 +08:00 via Android
    文本例子
    文本:第一个地址: http://g.cn 第二个地址: http://g.cn/1234

    替换后:第一个地址:<a href="http://g.cn">http://g.cn</a> 第二个地址:<a href="http://g.cn/1234">http://g.cn/1234</a>
    xixitalk
        7
    xixitalk  
    OP
       2016-10-01 09:42:40 +08:00 via Android
    正则表达式提取了整个 URL ,包括参数的
    xixitalk
        8
    xixitalk  
    OP
       2016-10-01 09:44:35 +08:00 via Android
    @ebony0319 不是,这是一个 URL,不是多个
    zjuhwc
        9
    zjuhwc  
       2016-10-01 09:46:06 +08:00 via iPhone
    你提取 URL 用的正则都可以提取出出 g.cng.cn/1234 两种情况,那替换的时候就用一样的规则替换啊
    xixitalk
        10
    xixitalk  
    OP
       2016-10-01 09:46:20 +08:00 via Android
    @xiaojj 正则替换吗?直接 replace 不好写吧
    xixitalk
        11
    xixitalk  
    OP
       2016-10-01 09:49:26 +08:00 via Android
    @zjuhwc 替换 g.cn 的时候会把 g.cn/1234 里前半部分替换掉,后者会变成<a href="http://g.cn">http://g.cn</a>/1234 这样的。
    zjuhwc
        12
    zjuhwc  
       2016-10-01 09:52:33 +08:00 via iPhone
    @xixitalk 你提取的时候是怎么做到提取的是 g.cn/1234 而不是 g.cn 的?
    zjuhwc
        13
    zjuhwc  
       2016-10-01 09:58:49 +08:00
    哦,看明白了,你想用 replace 。问题是你都用正则提取了,为啥不直接用正则替换。比如你提取用的是 re.match(pattern, string) ,你可以直接用 re.sub(pattern, repl, string, max=0) 做正则替换,复用之前的 pattern 啊
    buir
        14
    buir  
       2016-10-01 10:59:37 +08:00
    很简单 写个软件就可以了~
    aploium
        15
    aploium  
       2016-10-01 11:00:25 +08:00
    这是因为你正则写得不好啊
    自行 google 一下 "regex url"
    aploium
        16
    aploium  
       2016-10-01 11:04:34 +08:00
    还有正则引擎一般都带有 sub 功能的, 就是直接把匹配到的东西原地替换
    比如(Python)

    >>>re.sub(r"( http://go\.cn)",r"""<a href="\1">\1</a>""", "http://go.cn")
    <a href="http://go.cn">http://go.cn</a>
    moxiaonai
        17
    moxiaonai  
       2016-10-01 11:49:35 +08:00 via iPhone
    正则写的更准确一点应该能解决
    Shazoo
        18
    Shazoo  
       2016-10-01 12:39:42 +08:00
    1. 正则原地替换
    2. 如果觉得正则替换代码可读性低了点,不好维护,就在创建 list 的时候,保留这个 sub 字串的 pos ,后续在利用 pos 进行替换。

    粗略一想,没试验,用哪种,还是自己评估。


    不过我个人建议方案 1 。正则这东西,就是个坎,肯定得学习到一定程度的。长痛不如短痛,好好记忆吧。
    arnofeng
        19
    arnofeng  
       2016-10-01 13:40:22 +08:00 via iPhone
    正则没写好 你要匹配到斜杠的
    imn1
        20
    imn1  
       2016-10-01 14:53:06 +08:00
    还是没有说清楚格式
    如果每行一个 url
    ^(.+)$ -> <a href="$1">$1</a><br>
    就够了
    如果是没有分行,就要说清楚 url 之间是怎么分隔的
    xixitalk
        21
    xixitalk  
    OP
       2016-10-01 16:35:45 +08:00
    感谢,写了一个能用的

    def convertMsgToHTML(msg):
    #urls = re.findall('http[s]?://(?:#|[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', msg)
    msg = re.sub(r'( http[s]?://(?:#|[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)', r'<a href="\g<1>" target="_blank">\g<1></a>',msg,count=0,flags=re.UNICODE|re.MULTILINE)
    return msg

    测试:
    msg = u'''特殊 123 http://g.cn 456 http://g.cn/1234 78910 汉字
    '''
    text = convertMsgToHTML(msg)

    print text.encode('utf-8')


    输出结果:
    特殊 123 <a href="http://g.cn" target="_blank">http://g.cn</a> 456 <a href="http://g.cn/1234" target="_blank">http://g.cn/1234</a> 78910 汉字
    xixitalk
        22
    xixitalk  
    OP
       2016-10-01 16:51:19 +08:00
    我现在明白推特的 tweet 结构里不仅保存了缩短的地址 url ,还有展开地址 expand_url ,还有一个显示地址 disp_url 。不然推文转换成 html 太低效率了。

    缩短的地址保证了地址唯一性(当然还有数据统计方面的作用)
    展开地址是用户原始输入的地址
    显示地址保证了原始地址过长只显示前面 30 字节左右,排版美观。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1317 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 17:46 · PVG 01:46 · LAX 09:46 · JFK 12:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.