如何检测文本文件中无效的 utf8 unicode/二进制
- 2024-11-12 08:36:00
- admin 原创
- 20
问题描述:
我需要检测包含无效(非 ASCII)utf-8、Unicode 或二进制字符的损坏文本文件。
�>t�ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½w�ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½o��������ï¿ï¿½_��������������������o����������������������￿����ß����������ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½~�ï¿ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½}���������}w��׿��������������������������������������ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½~������������������������������������_������������������������������������������������������������������������������^����ï¿ï¿½s�����������������������������?�������������ï¿ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½w�������������ï¿ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½}����������ï¿ï¿½ï¿½ï¿½ï¿½y����������������ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½o�������������������������}��
我已尝试过:
iconv -f utf-8 -t utf-8 -c file.csv
这会将文件从 utf-8 编码转换为 utf-8 编码,并-c
跳过无效的 utf-8 字符。但是最后那些非法字符仍然被打印出来。在 Linux 或其他语言上的 bash 中还有其他解决方案吗?
解决方案 1:
假设您将语言环境设置为 UTF-8(参见locale
输出),这可以很好地识别无效的 UTF-8 序列:
grep -axv '.*' file.txt
解释(来自grep
手册页):
-a, --text:将文件视为文本,一旦发现无效的字节序列(不是 utf8),基本可以防止 grep 中止
-v, --invert-match:反转显示不匹配的行的输出
-x '.*' ( --line-regexp ):表示匹配由任意 utf8 字符组成的完整行。
因此,将会有输出,即包含无效的非 utf8 字节序列的行(因为反转了 -v)
解决方案 2:
我会grep
针对非 ASCII 字符。
使用带有 pcre 的 GNU grep(由于-P
,并不总是可用。在 FreeBSD 上,您可以使用包 pcre2 中的 pcregrep),您可以执行以下操作:
grep -P "[x80-xFF]" file
参考如何在 UNIX 中 grep 所有非 ASCII 字符。因此,实际上,如果您只想检查文件是否包含非 ASCII 字符,您可以这样说:
if grep -qP "[x80-xFF]" file ; then echo "file contains ascii"; fi
# ^
# silent grep
要删除这些字符,您可以使用:
sed -i.bak 's/[d128-d255]//g' file
这将创建一个file.bak
文件作为备份,而原始文件file
中的非 ASCII 字符将被删除。 参考从csv 中删除非 ASCII 字符。
解决方案 3:
尝试这个,以便从 shell 中查找非 ASCII 字符。
命令:
$ perl -ne 'print "$. $_" if m/[x80-xFF]/' utf8.txt
输出:
2 Pour être ou ne pas être
4 Byť či nebyť
5 是或不
解决方案 4:
您所看到的内容显然已损坏。显然,您正在显示以 Latin-1 呈现的文件;三个字符 � 代表三个字节值 0xEF 0xBF 0xBD。但这些是 Unicode替换字符 U+FFFD的 UTF-8 编码,这是尝试将未知或未定义编码的字节转换为 UTF-8 的结果,并且将正确显示为 �(如果您使用的是本世纪的浏览器,您应该会看到类似黑色菱形的东西,里面有一个问号;但这也取决于您使用的字体等)。
因此,关于“如何检测”这种特殊现象的问题很简单;Unicode 代码点 U+FFFD 是一个明显的迹象,也是您所暗示的过程中唯一可能的症状。
这些不是“无效的 Unicode”或“无效的 UTF-8”,因为这是一个有效的 UTF-8 序列,它编码了有效的 Unicode 代码点;只是这个特定代码点的语义是“这是一个无法正确表示的字符的替换字符”,即无效输入。
至于如何首先防止这种情况发生,答案非常简单,但也没有什么信息量——您需要确定错误编码发生的时间和方式,并修复产生此无效输出的过程。
要删除 U+FFFD 字符,请尝试类似
perl -CSD -pe 's/x{FFFD}//g' file
但同样,正确的解决方案是首先不要产生这些错误的输出。
要真正回答有关如何仅删除无效代码点的问题,请尝试
iconv -f UTF-8 -t UTF-8//IGNORE broken-utf8.txt >fixed-utf8.txt
(您没有透露示例数据的编码。它可能有额外的损坏。如果您向我们展示的是数据的 UTF-8 呈现的复制/粘贴,则它已被“双重编码”。换句话说,有人拿走了——如上所述已经损坏的——UTF-8 文本并告诉计算机将其从 Latin-1 转换为 UTF-8。撤消它很容易;只需将其“转换回”Latin-1。您获得的应该是多余的错误转换之前的原始 UTF-8 数据。
iconv -f utf-8 -t latin-1 mojibake-utf8.txt >fixed-utf8.txt
另请参阅mojibake。)
解决方案 5:
... 我正在尝试检测文件是否有损坏的字符。我也想删除它们。
我编写的 ugrep 实用程序使用 Unicode 扩展了 grep。使用 ugrep 只需一行:
ugrep -q -e "." -N "p{Unicode}" file.csv && echo "file is corrupted"
这与任何字符匹配,-e "."
但不是有效的 Unicode,因为-N "p{Unicode}"
它是“负模式”。
为了删除无效的 Unicode 字符,我们只想保留有效的字符:
ugrep "p{Unicode}" --format="%o" file.csv
这将使用自定义的方式写入结果--format="%o"
。
解决方案 6:
以下 C 程序检测无效的 utf8 字符。它已在 Linux 系统上测试和使用。
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
void usage( void ) {
printf( "Usage: test_utf8 file ...
" );
return;
}
int line_number = 1;
int char_number = 1;
char *file_name = NULL;
void inv_char( void ) {
printf( "%s: line : %d - char %d
", file_name, line_number, char_number );
return;
}
int main( int argc, char *argv[]) {
FILE *out = NULL;
FILE *fh = NULL;
// printf( "argc: %d
", argc );
if( argc < 2 ) {
usage();
exit( 1 );
}
// printf( "File: %s
", argv[1] );
file_name = argv[1];
fh = fopen( file_name, "rb" );
if( ! fh ) {
printf( "Could not open file '%s'
", file_name );
exit( 1 );
}
int utf8_type = 1;
int utf8_1 = 0;
int utf8_2 = 0;
int utf8_3 = 0;
int utf8_4 = 0;
int byte_count = 0;
int expected_byte_count = 0;
int cin = fgetc( fh );
while( ! feof( fh ) ) {
switch( utf8_type ) {
case 1:
if( (cin & 0x80) ) {
if( (cin & 0xe0) == 0xc0 ) {
utf8_1 = cin;
utf8_type = 2;
byte_count = 1;
expected_byte_count = 2;
break;
}
if( (cin & 0xf0) == 0xe0 ) {
utf8_1 = cin;
utf8_type = 2;
byte_count = 1;
expected_byte_count = 3;
break;
}
if( (cin & 0xf8) == 0xf0 ) {
utf8_1 = cin;
utf8_type = 2;
byte_count = 1;
expected_byte_count = 4;
break;
}
inv_char();
utf8_type = 1;
break;
}
break;
case 2:
case 3:
case 4:
// printf( "utf8_type - %d
", utf8_type );
// printf( "%c - %02x
", cin, cin );
if( (cin & 0xc0) == 0x80 ) {
if( utf8_type == expected_byte_count ) {
utf8_type = 1;
break;
}
byte_count = utf8_type;
utf8_type++;
if( utf8_type == 5 ) {
utf8_type = 1;
}
break;
}
inv_char();
utf8_type = 1;
break;
default:
inv_char();
utf8_type = 1;
break;
}
if( cin == '
' ) {
line_number ++;
char_number = 0;
}
if( out != NULL ) {
fputc( cin, out );
}
// printf( "lno: %d
", line_number );
cin = fgetc( fh );
char_number++;
}
fclose( fh );
return 0;
}
解决方案 7:
此 Perl 程序应删除所有非 ASCII 字符:
foreach $file (@ARGV) {
open(IN, $file);
open(OUT, "> super-temporary-utf8-replacement-file-which-should-never-be-used-EVER");
while (<IN>) {
s/[^[:ascii:]]//g;
print OUT "$_";
}
rename "super-temporary-utf8-replacement-file-which-should-never-be-used-EVER", $file;
}
它的作用是将文件作为命令行的输入,如下所示:
perl fixutf8.pl foo bar baz
然后,对于每一行,它将每个非 ASCII 字符的实例替换为空(删除)。
然后它将修改后的这一行写出到super-temporary-utf8-replacement-file-which-should-never-be-used-EVER
(命名以便它不会修改任何其他文件。)
之后,它将临时文件重命名为原始文件。
这接受所有 ASCII 字符(包括 DEL、NUL、CR 等),以防您对它们有特殊用途。如果您只想要可打印字符,只需将其替换为:ascii:
。希望
这对您有所帮助!如果这不是您要找的,请告诉我。:print:
`s///`
解决方案 8:
我可能重复了其他人已经说过的话。但我认为您的无效字符仍会被打印出来,因为它们可能是有效的。通用字符集试图引用全球常用的字符,以便能够编写不依赖于特殊字符集的强大软件。
因此,我认为您的问题可能是以下问题之一 - 假设您的总体目标是处理来自 utf 文件的这种(恶意)输入:
存在无效的utf8 字符(最好称为无效字节序列- 对于这一点,我想参考相应的Wikipedia 文章)。
您当前的显示字体中缺少等效字符,这些等效字符被特殊符号替换或显示为其二进制 ASCII 等效字符(fe - 因此我想参考以下帖子:UTF-8 特殊字符不会显示)。
因此,我认为有两种方法来解决这个问题:
将所有字符从 utf8转换为可处理的内容 - fe ASCII - 可以使用 fe 完成
iconv -f utf-8 -t ascii -o file_in_ascii.txt file_in_utf8.txt
。但要小心,从较宽的字符空间(utf)转移到较小的字符空间可能会导致数据丢失。正确处理 utf(8) - 这就是世界编写内容的方式。如果您认为由于任何限制性后处理步骤而可能不得不依赖 ASCII 字符,请停下来重新思考。在大多数情况下,后处理器已经支持 utf,最好找出如何使用它。您正在使您的内容面向未来且防弹。
处理 utf 可能看起来很棘手,以下步骤可以帮助您实现 utf-readyness:
能够正确显示 utf 或确保您的显示堆栈(操作系统、终端等)能够显示足够的 unicode 子集(当然,这应该可以满足您的需求),这在许多情况下可以避免使用十六进制编辑器。不幸的是,utf 太大,无法用一种字体显示,但这篇文章是一个很好的起点:https: //stackoverflow.com/questions/586503/complete-monospaced-unicode-font
能够过滤无效的字节序列。有很多方法可以实现这一点,这篇 ul-post 展示了其中的多种方法:过滤无效的 utf8 - 我想特别指出第 4 个答案,它建议使用
uconv
它来为无效序列设置回调处理程序。阅读有关unicode的更多信息。
解决方案 9:
使用 Ubuntu 22.04,我通过使用以下命令获得更正确的答案:
grep -axv -P '.*' file.txt
没有 -P 的原始答案似乎对许多亚洲字符给出了误报,例如:
<lei:LegalName xml:lang="ko">피씨에이생명보험주식회사</lei:LegalName>
<lei:LegalName xml:lang="ko">린드먼 부품소재 전문투자조합 1</lei:LegalName>
<lei:LegalName xml:lang="ko">비엔피파리바 카디프손해보험 주식회사</lei:LegalName>
这些字符确实通过了实用程序的扫描isutf8
。
解决方案 10:
Python 3 中一个非常肮脏的解决方案
import sys
with open ("cur.txt","r",encoding="utf-8") as f:
for i in f:
for c in i:
if(ord(c)<128):
print(c,end="")
输出应为:
>two_o~}}w~_^s?w}yo}
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件