2010-07-16 171 views
29

如何从文件中删除非ASCII字符?删除文件中的非ASCII字符

+4

有一个非常类似的线程在这里,询问有关在UNIX文件中找到非ASCII字符:HTTP://堆栈溢出。com/questions/3001177/how-do-i-grep-for-non-ascii-characters-in-unix – hotshot309 2012-06-18 16:01:54

回答

56

如果你想使用Perl,像这样做:

perl -pi -e 's/[^[:ascii:]]//g' filename 

详解

下面的解释涵盖了上面的命令假设读者的每一个部分是不熟悉解决方案中的任何...

  • perl

    运行perl解释器。 Perl是一种编程语言,通常可在所有类Unix系统上使用。该命令需要在shell提示符下运行。

  • -p

    -p标志告诉Perl在输入文件中的每一行迭代,在各行指定的命令(后述),然后打印结果。这相当于将您的Perl程序包装在while(<>) { /* program... */; } continue { print; }中。有一个类似的-n标志可以完成相同的操作,但省略了continue { print; }块,所以如果您想进行自己的打印,则可以使用该标志。

  • -i

    -i标志告诉perl的输入文件是在地方和输出应该返回到该文件进行编辑。这对于实际修改文件很重要。省略此标志会将输出写入STDOUT,然后您可以将其重定向到新文件。

    注意,你不能忽略-i和重定向STDOUT输入文件为已读之前,这将痛殴输入文件。这就是shell的工作原理,与perl无关。 -i标志智能地解决了这个问题。

    Perl和外壳让你多单字符参数组合成一个这就是为什么我们可以用-pi代替-p -i

    -i标志带一个参数,它是一个文件扩展名,如果你想使用做一个原始文件的备份,所以如果你使用-i.bak,那么perl会在进行更改之前将输入文件复制到filename.bak。在这个例子中我省略了创建一个备份,因为我希望你将使用版本控制反正:)

  • -e

    -e标志告诉perl的下一个参数是封装在一个完整的Perl程序串。如果你有一个很长的程序,那么这并不总是一个好主意,因为这个程序可能无法读取,但是通过我们这里的一个命令程序,它的简洁性可以提高易读性。

    注意,我们不能-e标志和-i标志作为二者的结合参加一个参数,和Perl将认为第二个标志是参数,因此,举例来说,如果我们使用-ie <program> <filename>, perl会假设<program><filename>都是输入文件,并尝试创建<program>e<filename>e,前提是e是要用于备份的扩展。这将失败,因为<program>不是一个真正的文件。反过来(-ei)也不会工作,因为perl会尝试执行i作为一个程序,这会导致编译失败。

  • s/.../.../

    这是Perl的正则表达式基础替换操作符。它有四个参数。第一个出现在操作员面前,如果未指定,则使用默认值$_。第二个和第三个符号在/之间。第四个是在最后的/之后,在这种情况下是g

    • $_在我们的代码中,第一个参数是$_其是在Perl的默认循环变量。如上所述,-p标志将我们的程序包装在while(<>)中,该程序创建一个while循环,从输入中一次读取一行(<>)。它隐含地将该行分配给$_,并且如果未指定,则采用单个参数的所有命令都将使用该行(例如:只是调用print;实际上将转换为print $_;)。因此,在我们的代码中,s/.../.../运算符在输入文件的每一行上运行一次。

    • [^[:ascii:]]第二个参数是要在输入字符串中搜索的模式。这个模式是一个正则表达式,所以包含在[]内的任何东西都是一个括号表达式。本节可能是本示例中最复杂的部分,因此我们将在最后详细讨论它。

    • <empty string>第三个参数是替换字符串,在我们的例子中是空字符串,因为我们要删除所有非ascii字符。

    • g第四个参数是替换运算符的修饰符标志。 g标志指定替代在输入中的所有匹配中应该是全局的。没有这个标志,只有第一个实例会被替换。其他可能的标志是不区分大小写的匹配的i,仅与多行字符串相关的sm(这里我们有单行字符串),o,它指定该模式应该被预编译(这对于长文件可能是有用的)和x,它指定该模式可以包含空格和注释以使其更易读(但如果是这种情况,我们不应该在单行上写我们的程序)。

  • filename

    这是包含我们想去掉非ASCII字符输入文件。

[^[:ascii:]]

所以,现在让我们来详细讨论[^[:ascii:]]

如上所述,正则表达式中的[]指定了括号表达式,该表达式指示正则表达式引擎匹配输入中与表达式内字符集中任何一个字符匹配的单个字符。因此,例如,[abc]将匹配abc,并且它将仅匹配单个字符。使用^作为第一个字符反转匹配,所以[^abc]将匹配不是a,bc的任何一个字符。

但括号内的[:ascii:]表达式呢?

如果您有一个基于unix的系统,请在命令行运行man 7 re_format来阅读手册页。如果不是,read the online version

[:ascii:]是一个字符类,它代表整个ascii字符集,但这种字符类只能在括号表达式中使用。使用此的正确方法是[[:ascii:]],它可能会与上面的abc情况一样否定,或者与括号表达式结合在其他字符中,因此,例如,[éç[:ascii:]]将匹配所有ascii字符以及éç,它们不是ascii,和[^éç[:ascii:]]将匹配所有不是ascii的字符,也不匹配éç

+0

只是在看到您的评论之前做到了这一点。 – janar 2010-07-17 07:50:10

+0

@bluesmoon你可以分解这件事并解释发生了什么? – 2016-10-09 12:48:58

+3

@JoshuaRobinson我用一个详细的解释编辑了答案。 – bluesmoon 2016-10-12 16:52:03

8
tr -dc [:graph:][:cntrl:] < input-file > cleaned-file 

这是假设你想保留“控制”字符和“可打印”字符。根据需要拨弄。

+3

'tr -dc'\ 11 \ 12 \ 15 \ 40- \ 176'文件'控制字符可以包含很多东西 – user3338098 2015-08-27 22:44:10

1

我的two cents:它可能无法解决您的问题,但它可能会给你一些提示。

file命令告诉您文件编码,即UTF,ASCII等,iconv可以在不同的编码之间转换文件。

+1

iconv令人惊讶地在xml文件上剥离了一些其他的东西..我做了iconv -f ascii -t ascii -c – janar 2010-07-17 07:49:26

5
perl -pe's/[[:^ascii:]]//g' <input.txt> output.txt 
+1

这正是我所做的解决这个问题。 – janar 2010-07-17 07:48:34

3

您可以编写一个C程序是这样的:避免了为简单起见,错误检查:

#include <stdio.h> 
#include <ctype.h> 

int main(int argc, char **argv) 
{ 
    FILE *fin = fopen("source_file", "rb"); 
    FILE *fout = fopen("target_file", "w"); 
    int c; 
    while ((c = fgetc(fin)) != EOF) { 
     if (isprint(c)) 
      fputc(c, fout); 
    } 
    fclose(fin); 
    fclose(fout); 
    return 0; 
} 

注意。

与编译:

$ gcc -W source_code.c -o convert 

与运行:

$ ./convert