-1

我正在编写一个 Python 3.2 脚本来查找 Unicode XML 格式的文本文件中在 XML 1.0 中无效的字符。该文件本身不是 XML 1.0,因此它可以轻松包含 1.1 及更高版本支持的字符,但使用它的应用程序只能处理 XML 1.0 中有效的字符,因此我需要找到它们。

XML 1.0 不支持 \u0001-\u0020 范围内的任何字符,\u0009、\u000A、\u000D 和 \u0020 除外。除此之外,\u0021-\uD7FF 和 \u010000-\u10FFFF 也是支持的范围,但仅此而已。在我的 Python 代码中,我以这种方式定义了该正则表达式模式:

re.compile("[^\u0009\u000A\u000D\u0020\u0021-\uD7FF\uE000-\uFFFD\u010000-\u10FFFF]")

但是,下面的代码在我的示例文件中没有找到已知的错误字符(\u0007,'bell' 字符。)不幸的是,我无法提供示例行(专有数据)。

我认为问题出在两个地方之一:要么是错误的正则表达式模式,要么是我如何打开文件并按行读取 - 即编码问题。当然,我可能是错的。

这是相关的代码片段。

processChunkFile()接受三个参数:chunkfile是文件的绝对路径(在这种情况下,原始文件的 500,000 行的“块”)可能包含也可能不包含坏字符。outputfile是要写入输出的可选的、预先存在的文件的绝对路径。verbose是一个布尔标志,用于启用更详细的命令行输出。其余代码只是获取命令行参数(使用argparse)并将单个大文件分解为较小的文件。(原始文件通常大于 4GB,因此需要“分块”。)

def processChunkFile(chunkfile, outputfile, verbose):
    """
    Processes a given chunk file, looking for XML 1.0 chars.
    Outputs any line containing such a character.
    """
    badlines = []

    if verbose:
        print("Processing file {0}".format(os.path.basename(chunkfile)))

    # open given chunk file and read it as a list of lines
    with open(chunkfile, 'r') as chunk:
        chunklines = chunk.readlines()

        # check to see if a line contains a bad character;
        # if so, add it to the badlines list
        for line in chunklines:
            if badCharacterCheck(line, verbose) == True:
                badlines.append(line)

    # output to file if required
    if outputfile is not None:
        with open(outputfile.encode(), 'a') as outfile:
            for badline in badlines:
                outfile.write(str(badline) + '\n')

    # return list of bad lines
    return badlines



def badCharacterCheck(line, verbose):
    """
    Use regular expressions to seek characters in a line
    which aren't supported in XML 1.0.
    """
    invalidCharacters = re.compile("[^\u0009\u000A\u000D\u0020\u0021-\uD7FF\uE000-\uFFFD\u010000-\u10FFFF]")
    matches = re.search(invalidCharacters, line)
    if matches:
        if verbose:
            print(line)
            print("FOUND: " + matches.groups())
        return True

    return False
4

2 回答 2

1
\u010000

Python\u转义只有四位数字,因此 U+0100 后跟两个 U+0030 数字零。对 BMP 之外的字符使用带有八位数字的大写 U 转义:

\U00010000-\U0010FFFF

请注意,这和您的表达式通常不适用于 Python 的“窄构建”,其中字符串基于 UTF-16 代码单元,BMP 之外的字符作为两个代理代码单元处理。(窄版本是 Windows 的默认设置。谢天谢地,它们在 Python 3.3 中消失了。)

它可以轻松包含 1.1 及更高版本支持的字符

(虽然 XML 1.1 只能包含那些被编码为数字字符引用的字符&#...;,所以文件本身可能仍然不是格式正确的。)

打开(块文件,'r')

你确定块文件是编码的locale.getpreferredencoding吗?

原始文件通常大于 4GB,因此需要“分块”。

呃,怪物 XML 很痛苦。但是使用合理的流 API(和文件系统!)应该仍然可以处理。例如在这里,您可以使用一次处理每一行,for line in chunk:而不是使用一次读取所有块readlines()

re.search(无效字符,行)

因为invalidCharacters已经是一个编译的模式对象,你可以invalidCharacters.search(...).

说了这么多,对我来说它仍然匹配 U+0007 贝尔。

于 2013-10-16T00:15:35.773 回答
0

删除两个已知标记或字符串中两个已知字符之间的单词、字符、字符串或任何内容的最快方法是使用直接和本机 C 方法,使用 RE 和 Common,如下所示。

var = re.sub('<script>', '<!--', var)
var = re.sub('</script>', '-->', var)
#And finally
var = re.sub('<!--.*?-->', '', var)

它比 Beautiful Soup 去除所有东西并且工作得更快、更好、更清洁。批处理文件是“”开始的地方,并且仅被借用用于本机 C 的批处理和 html”。当使用带有正则表达式的所有 Pythonic 方法时,您必须意识到 Python 并没有改变或改变所有使用的正则表达式通过机器语言,当单个循环可以在一次迭代中将所有内容作为一个块找到时,为什么要迭代多次呢?对 Characters 也可以单独执行相同的操作。

var = re.sub('\[', '<!--', var)
var = re.sub('\]', '-->', var)
#And finally
var = re.sub('<!--.*?-->', '' var)#wipes it all out from between along with.

你不需要美丽的汤。如果您了解其工作原理,您也可以使用它们来剥头皮数据。

于 2017-04-23T11:51:50.583 回答