【问题标题】:Perl "scrub" characters while parsingPerl在解析时“擦洗”字符
【发布时间】:2016-04-28 13:51:52
【问题描述】:

我正在解析一个文件 - 我要做的第一件事是将前三个字段连接起来,并将它们添加到每条记录的前面。然后我想擦洗任何冒号、单引号、双引号或反斜杠的数据。以下是我的做法,但有没有办法让我使用 $line 变量更有效?

# Read the lines one by one.
while($line = <$FH>) {

# split the fields, concatenate the first three fields,
# and add it to the beginning of each line in the file
    chomp($line);
    my @fields = split(/,/, $line);
    unshift @fields, join '_', @fields[0..2];

# Scrub data of characters that cause scripting problems down the line.
        $_ =~ s/:/ /g for @fields[0..39];
        $_ =~ s/\'/ /g for @fields[0..39];
        $_ =~ s/"/ /g for @fields[0..39];
        $_ =~ s/\\/ /g for @fields[0..39];

【问题讨论】:

  • 您可能应该在这里颠倒您的逻辑,即对于每个字段,应用所有这些替换。我认为这里的正确答案是你应该使用像Text::CSV_XS 这样的模块,然后你就不需要做任何卫生工作了。
  • 它们不需要“可用”。你设法安装了你的脚本,所以你也可以设法安装那些称为模块的脚本。
  • 要么你有权限在上面放 Perl 代码,要么你没有,所以你有足够的权限来安装 Perl 模块。
  • @BigRedEO You don't need root/admin privileges to install modules. 不使用模块会让你的生活变得更加困难。如果没有必要,不要重新发明轮子。
  • @HunterMcMillen: “你应该使用像 Text::CSV_XS 这样的模块,然后你就不需要做任何卫生工作了” 我希望这是真的,但是@ 987654325@ 经常被视为万灵药。 OP 正在从数据中删除单引号和双引号、冒号和反斜杠,并且该模块不会执行此类操作。偶尔会出现一个 CSV 文件,最好使用 Text::CSV 进行解析,它通常是 Microsoft Excel 的输出。其余时间,一个简单的chomp 后跟split /,/ 是更好的选择

标签: perl parsing data-scrubbing


【解决方案1】:

什么对我来说更干净:

while($line = <$FH>) {
    chomp($line);

    $line =~ s/[:\'"\\]/ /g;

    my @fields = split(/,/, $line);
    unshift @fields, join '_', @fields[0..2];
}

正如@HunterMcMillen 所说,如果这是一个标准的 CSV 文件,最好使用解析模块。以后会更容易。

【讨论】:

  • 那个人会在任何领域的中间杀死一个“。
  • @Sebastian - 它会删除任何 " 字符。这就是他正在做的事情......还是我错过了你的意思?
  • eballes - 没有可供我使用的文本模块(它们也将不可用)。 @Sebastian - 不清楚你在说什么。
  • 1,2,foo "bar" baz,"don't try this at home" 将变为 1, 2, foo bar baz, dont try this at home - 您在 $line 上的解决方案基本上会从行中的任何位置删除所有特殊字符 - 即使在字段(列)的中间。
  • @BigRedEO:你没有正确描述你的问题。人们想出的代码可以按照你的意思实现他们最好的,你说“是的,但我也有这个……”。想象一下@eballes 的感受。这不是获得答案的好方法。听起来您需要将每条记录拆分为字段并为每个字段指定一个转换。我认为如果您自己无法取得进展,您必须打开一个新问题
【解决方案2】:

我确信我以前见过一个非常相似的问题,但我的简单搜索不会找到它。突出的是在所有其他字段之前添加一个新字段,它是原始值的函数

你已经用 Perl 术语描述得最好了

unshift @fields, join '_', @fields[0..2];

所以剩下的唯一步骤就是删除流氓字符——单引号和双引号、冒号和反斜杠

您的代码似乎运行良好。我要做的唯一改变是

  • 正确使用默认变量$_。我认为这是新人最讨厌 Perl 的地方,一旦他们了解了它就会爱上它

  • 使用tr///d 而不是s///。它可能会增加一点速度,但最重要的是,当您只想说出要删除的字符并需要更简单的内容时,您可以从正则表达式语法中解放出来

我认为这应该满足您的需求

use strict;
use warnings 'all';

while ( <DATA> ) {

    chomp;
    my @fields = split /,/;

    unshift @fields, join '_', @fields[0..2];

    tr/:"'\\//d for @fields; # Delete colons, quotes, and backslash

    print join(',', @fields), "\n";
}

__DATA__
a:a,b"bb",c'ccc',ddd,e,f,g,h

输出

aa_bbb_cccc,aa,bbb,cccc,ddd,e,f,g,h

【讨论】:

  • 每条记录的最后两个字段中都会有冒号,必须保留在记录中,因此我将冒号分开,以便最后两个字段保持不变。这将如何改变您上面的答案?
  • @BigRedEO:谢谢。但请记住,没有人知道您的记录超过 40 个字段。你现在才透露,从 41 岁起,你需要不同的待遇。这就是为什么显示样本输入数据和相应的所需输出数据很重要的原因之一。我认为您的问题陈述不会走得太远
猜你喜欢
  • 2014-07-19
  • 2019-05-07
  • 1970-01-01
  • 2021-06-17
  • 2013-06-22
  • 2015-03-11
  • 2012-06-20
  • 2013-02-04
  • 1970-01-01
相关资源
最近更新 更多