Python 多个正则表达式替换

4 投票
2 回答
1016 浏览
提问于 2025-04-17 10:50

我是一名Python新手。
我搜索了好几天,但只找到了一些零碎的概念。
我在Windows上使用Python 2.7(我选择Python是因为它可以在多个平台上使用,结果可以在Windows上移植)。

我想写一个脚本,搜索一个文件夹里的所有*.txt UTF-8文本文件,逐个加载内容,把非ASCII字符转换成HTML实体,然后在每行的开头和结尾添加HTML标签。开头和结尾的标签有两种,开头的标签和结尾的标签之间用一个空行分隔。最后,所有的结果要写入另一个文本文件,比如*.htm。为了更直观:

unicode1.txt:

űnícődé text line1
űnícődé text line2
[empty line]
űnícődé text line3
űnícődé text line4

结果应该在unicode1.htm中:

<p class='aaa'>&#369;n&iacute;c&#337;d&eacute; text line1</p>
<p class='aaa'>&#369;n&iacute;c&#337;d&eacute; text line2</p>
[empty line]
<p class='bbb'>&#369;n&iacute;c&#337;d&eacute; text line3</p>
<p class='bbb'>&#369;n&iacute;c&#337;d&eacute; text line3</p>

我开始开发我的解决方案的核心部分,但遇到了瓶颈。看看我的脚本版本(为了简单起见,我选择用xmlcharrefreplace进行编码)。

版本1:

import re, cgi, fileinput
file="_utf8.txt"
text=""
for line in fileinput.input(file, inplace=0):
  line=cgi.escape(line.decode('utf8'),1).encode('ascii', 'xmlcharrefreplace')
  line=re.sub(r"^", "<p>", line, 1)
  text=text+re.sub(r"$", "</p>", line, 1)
print text

这个版本有效,结果不错,但我觉得对于这个任务,fileinput不是一个合适的方法。

版本2:

import re, cgi, codecs
file="_utf8.txt"
text=""
f=codecs.open(file, encoding='utf-8')
for line in f:
  line=cgi.escape(line,1).encode('ascii', 'xmlcharrefreplace')
  line=re.sub(r"^", "<p>", line, 1)
  text=text+re.sub(r"$", "</p>", line, 1)
f.close()
print text

这个版本搞乱了结果,关闭标签在行首替换了第一个字母等等。

版本3(尝试了多行标志):

import re, cgi, codecs
file="_utf8.txt"
text=""
f=codecs.open(file, encoding='utf-8')
for line in f:
  line=cgi.escape(line,1).encode('ascii', 'xmlcharrefreplace')
  line=re.sub(r"^", "<p>", line, 1, flags=re.M)
  text=text+re.sub(r"$", "</p>", line, 1, flags=re.M)
f.close()
print text

结果一样。

版本4(尝试用一个正则表达式代替两个):

import re, cgi, codecs
file="_utf8.txt"
text=""
f=codecs.open(file, encoding='utf-8')
for line in f:
  line=cgi.escape(line,1).encode('ascii', 'xmlcharrefreplace')
  text=text+re.sub(r"^(.*)$", r"<p>\1</p>", line, 1)
f.close()
print text

结果还是一样。请帮帮我。

编辑:我刚用十六进制编辑器检查了结果文件,发现每个关闭标签前都有一个x0D字节!为什么会这样?

编辑2:为了更合逻辑的处理做了一些修改

text+=re.sub(r"^(.*)$", r"<p>\1</p>", line, 1)

编辑3:通过十六进制编辑器我发现了搞乱结果的原因:每个CRLF前都有额外的CR(x0D)字节。
我追踪到了CR问题,导致这个问题的是用+进行的字符串连接。

# -*- coding: utf-8 -*-
text=""
f=u"unicode text line1\r\n unicode text line2"
for line in f:
  text+=line
print text

这导致了:

unicode text line1\r\r\n unicode text line2

有什么想法,如何解决这个问题吗?

2 个回答

3

这里根本不需要用到正则表达式,直接这样做就行:

with open('utf8.txt') as f:
    class_name = 'aaa'
    for line in f:
        if line == '\n':
            classname = 'bbb'
        else:
            # decode / convert line
            line = '<p class="{0}">{1}</p>\n'.format(class_name, line.rstrip())
        # write line to file

你得到的结果看起来并不是因为正则表达式的问题,因为它们似乎是正确的。问题很可能出在你进行编码或转换的那一行。把那一行打印出来,不加标签,看看结果是否符合预期。

1
#!/usr/bin/env python
import cgi
import fileinput
import os
import shutil
import sys

def textfiles(rootdir, extensions=('.txt',)):
    for dirpath, dirs, files in os.walk(rootdir):
        for f in files:
            if f.lower().endswith(extensions):
               yield os.path.join(dirpath, f)

def htmlfiles(files):
    for f in files:
        root, _ = os.path.splitext(f)
        newf = root + '.html'
        shutil.copy2(f, newf)
        yield newf

for line in fileinput.input(htmlfiles(textfiles(sys.argv[1])), inplace=True):
    if fileinput.isfirstline():
       klass = 'aaa' # start head part
    line = cgi.escape(line.decode('utf-8').strip())
    line = line.encode('ascii', 'xmlcharrefreplace')
    if not line: # empty line
       klass = 'bbb' # start tail part
       print(line)
    else:
       print('<p class="%s">%s</p>' % (klass, line))
$ python txt2html.py c:\root\dir

这是一个链接,点击后可以查看一个示例代码,地址是 http://ideone.com/Bfu8k

撰写回答