XML 1.0 では無効な Unicode XML 形式のテキスト ファイル内の文字を検索する Python 3.2 スクリプトを作成しています。ファイル自体は XML 1.0 ではないため、1.1 以降でサポートされている文字を簡単に含めることができますが、それを使用するアプリケーションは XML 1.0 で有効な文字しか処理できないため、それらを見つける必要があります。
XML 1.0 は、\u0009、\u000A、\u000D、および \u0020 を除いて、\u0001-\u0020 の範囲の文字をサポートしていません。その上では、\u0021-\uD7FF と \u010000-\u10FFFF もサポートされている範囲ですが、それ以外はありません。私の Python コードでは、正規表現パターンを次のように定義しています。
re.compile("[^\u0009\u000A\u000D\u0020\u0021-\uD7FF\uE000-\uFFFD\u010000-\u10FFFF]")
ただし、以下のコードでは、サンプル ファイルに既知の悪い文字 (\u0007、「ベル」文字) が見つかりません。残念ながら、サンプル行 (独自のデータ) を提供することはできません。
問題は次の 2 つの場所のいずれかにあると思います。正規表現パターンが悪いか、ファイルを開いて行単位で読み取る方法、つまりエンコードの問題です。もちろん、私は間違っているかもしれません。
関連するコード スニペットを次に示します。
processChunkFile()
3 つのパラメータを取ります: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