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

时间:2015-12-04 16:51:47

标签: python regex

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

我尝试使用正则表达式执行此操作,但我的输出是 " 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 个答案:

答案 0 :(得分:3)

您可以使用前瞻和后瞻断言:

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]

答案 1 :(得分:1)

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

即使子工作符合您的期望,您的正则表达式也会缺少数字是URL的一部分的边缘情况,例如www.2048game.com。 定义IP看起来更容易。它总是一组四个数字,每个数字有一个,两个或三个数字,用点分隔。 (无论如何,在IPv4的情况下。但IPv6不使用句点,所以这里没关系。)

假设您的文本文件中只有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检测。见In search of the perfect URL validation regex

答案 2 :(得分:0)

您必须在点之前和之后存储[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 :(得分: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