用于查找XML 1.0不支持的字符的Python正则表达式不会返回任何结果

时间:2013-10-15 15:02:24

标签: python xml regex unicode python-3.x

我正在编写一个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

2 个答案:

答案 0 :(得分:1)

\u010000

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

\U00010000-\U0010FFFF

请注意,这个和你的表达式一般不适用于Python的“窄版本”,其中字符串基于UTF-16代码单元,BMP之外的字符作为两个代理代码单元处理。 (狭义的构建是Windows的默认构建。幸运的是,它们取消了Python 3.3。)

  

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

(尽管XML 1.1在将它们编码为数字字符引用&#...;时只能包含这些字符,因此文件本身可能仍然没有格式良好。)

  

open(chunkfile,'r')

你确定chunkfile是用locale.getpreferredencoding编码的吗?

  

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

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

  

re.search(invalidCharacters,line)

由于invalidCharacters已经是已编译的模式对象,因此您只需invalidCharacters.search(...)

说完这一切之后,它仍然适合我与U + 0007贝尔。

答案 1 :(得分:0)

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

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

它删除了一切,比美丽的汤更快,更好,更清洁。批处理文件是“”从那里开始并且仅用于从本地C的批处理和html中使用。“当使用所有Pythonic方法和正则表达式时,你必须意识到Python没有改变或改变所有使用的正则表达式通过机器语言,为什么当一个循环在一次迭代中将它全部作为一个块发现时,为什么要迭代很多次呢?同样也单独使用字符。

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

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