首页 文章

Python:在特定条件下使用正则表达式查找和替换

提问于
浏览
2

基本上我想写一个将清理URL的脚本,用"(dot)"字符串替换点 . 例如,如果我在运行脚本后http://www.google.com,我希望它是http://www(dot)google(dot) . 当我的文本文件只包含网址或其他字符串时,这很容易用.replace实现,但在我的情况下,我的文本文件中也有IP地址,我不希望IP地址中的点更改为"(dot)" .

我尝试使用正则表达式,但我的输出是“http://ww(dot)oogl(dot)om 192.60.10.10 33.44.55.66”

这是我的代码

from __future__ import print_function


import sys
import re

nargs = len(sys.argv)
if nargs < 2:

    sys.exit('You did not specify a file')
else:
    inputFile = sys.argv[1]
    fp = open(inputFile)
    content = fp.read()

replace = '(dot)'
regex = '[a-z](\.)[a-z]'
print(re.sub(regex, replace, content, re.M| re.I| re.DOTALL))

我想我需要有一个条件来检查模式是否为number.number - 不要替换 .

4 回答

  • 1

    您必须在点之前和之后存储 [a-z] 内容,以便将其再次放入替换后的字符串中 . 我在这里解决了它:

    from __future__ import print_function
    import sys
    import re
    
    nargs = len(sys.argv)
    if nargs < 2:
        sys.exit('You did not specify a file')
    else:
        inputFile = sys.argv[1]
        fp = open(inputFile)
        content = fp.read()
    
    replace = '\\1(dot)\\3'
    regex = '(.*[a-z])(\.)([a-z].*)'
    print(re.sub(regex, replace, content, re.M| re.I| re.DOTALL))
    
  • 3

    你可以使用lookahead和lookbehind断言:

    import  re
    
    s = "http://www.google.com 127.0.0.1"
    
    print(re.sub("(?<=[a-z])\.(?=[a-z])", "(dot)", s))
    http://www(dot)google(dot)com 127.0.0.1
    

    为了工作字母和数字,这应该有把戏,确保至少有一个字母:

    s = "http://www.googl1.2com 127.0.0.1"
    
    print(re.sub("(?=.*[a-z])(?<=\w)\.(?=\w)", "(dot)", s, re.I))
    
    http://www(dot)googl1(dot)2com 127.0.0.1
    

    对于您的文件,您需要 re.M

    In [1]: cat test.txt
    google8.com
    google9.com
    192.60.10.10
    33.44.55.66
    google10.com
    192.168.1.1
    google11.com
    
    In [2]: with open("test.txt") as f:
       ...:         import re
       ...:         print(re.sub("(?=.*[a-z])(?<=\w)\.(?=\w)", "(dot)", f.read(), re.I|re.M))
       ...:     
    google8(dot)com
    google9(dot)com
    192.60.10.10
    33.44.55.66
    google10(dot)com
    192.168.1.1
    google11(dot)com
    

    如果文件很大并且内存是个问题,你也可以逐行进行,要么将所有行存储在列表中,要么在使用每行时:

    import re
    with open("test.txt") as f:
        r = re.compile("(?=.*[a-z])(?<=\w)\.(?=\w)", re.I)
        lines = [r.sub("(?=.*[a-z])(?<=\w)\.(?=\w)", "(dot)") for line in f]
    
  • 0

    根据您的代码判断,您希望替换模式中的第一个组 . 但是, re.sub 替换整个匹配模式,而不是组 . 在你的情况下,这是句点之前的单个字符,句点本身和它之后的单个字符 .

    即使子工作符合您的期望,您的正则表达式也会缺少数字是URL的一部分,例如 www.2048game.com . 定义IP看起来更容易 . 它's always a set of four numbers with one, two or three digits each, separated by dots. (In the case of IPv4, anyway. But IPv6 does not use periods, so it doesn'在这里 . )

    假设您的文本文件中只有URL和IP,只需过滤掉所有IP,然后替换其余URL中的句点:

    is_ip = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
    urls = content.split(" ")
    for i, url in enumerate(urls):
        if not is_ip.match(url):
            urls[i] = url.replace('.', '(dot)')
    content = ' '.join(urls)
    

    当然,如果您在 content 中有常规文本,这也将替换所有常规时段,而不仅仅是URL . 在这种情况下,您首先需要更复杂的URL检测 . 见In search of the perfect URL validation regex

  • 0
    import re
    
    content = "I tried to do this using regex, but my output is http://www.googl.com 192.60.10.10 33.44.55.66\nhttp://ya.ru\n..."
    
    reg = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
    
    all_urls = re.findall(reg, content, re.M| re.I| re.DOTALL)
    repl_urls = [u.replace('.', '(dot)') for u in all_urls]
    
    for u, r in zip(all_urls, repl_urls):
        content = content.replace(u, r)
    
    print content
    

相关问题