【问题标题】:regex match non white space characters except new line with perl正则表达式匹配除 perl 换行之外的非空白字符
【发布时间】:2017-09-20 11:23:38
【问题描述】:

我想匹配第五列,即“,,”和“,,,”和“,”,除了新行,即“\n”,然后用某个值替换它们。以下是由空格分隔的文件。我尝试了以下代码: 注意:尽管该示例在第五列中显示了逗号。它可以是除换行符 (\n) 之外的任何字符(包括制表符 \t)。

my $delimiter="**";
my $dir_to_check=$DIR; 
opendir my $DIR, $dir_to_check or die "Error in opening dir '$dir_to_check' because: $!";
    my @files = readdir($DIR);
    closedir($DIR);
    foreach my $file (@files)
    {
            if($file =~ /\.fmt/)
            {
                unless ( open( CONTRL_FILE, "< $dir_to_check/$file" ) ) {
                    print "error while opening file $dir_to_check/$file \n"
                }   # UNLESS


               if ($file eq 'test.fmt')
               {
                    unless ( open( CONTRL_FILE_1, "> $dir_to_check/$file.temp" ) ) {
                    print "error while opening file $file \n"
                    }   # UNLESS
                    while(<CONTRL_FILE>)
                    {

                            $_ =~ s/"[^\s]+"/"$delimiter"/ ;
                            print CONTRL_FILE_1 $_;

                    }
                    close(CONTRL_FILE_1);
               }
            }
    }

数据:

1       SQLCHAR             0       5       ",,,"      1     ""
2       SQLCHAR             0       25      ",,,,"      2     ""
3       SQLCHAR             0       1       ","      3     ""
4       SQLCHAR             0       12      ","      4     ""
5       SQLCHAR             0       1       "\n"     5     ""

结果:

1       SQLCHAR             0       5       "*****"      1     ""
2       SQLCHAR             0       25      "*****"      2     ""
3       SQLCHAR             0       1       "*****"      3     ""
4       SQLCHAR             0       12      "*****"      4     ""
5       SQLCHAR             0       1       "*****"     5     ""

预期结果:

1       SQLCHAR             0       5       "**"      1     ""
2       SQLCHAR             0       25      "**"      2     ""
3       SQLCHAR             0       1       "**"      3     ""
4       SQLCHAR             0       12      "**"      4     ""
5       SQLCHAR             0       1       "\n"     5     ""

【问题讨论】:

  • 实际上在上面的例子中它是逗号,但它可以是非空白字符的任意组合。
  • 你可以试试:perl -pe 's/(?&lt;=")[^ \\]+(?=")/*****/g;' file 吗?
  • 代替[^\s]+ 使用:[^ \\] 也可以忽略\n
  • ^[^"\v]*?"\K((?!\\n)[^"\v]+)(?=") 使用m 修饰符和** 作为替代?
  • @ctwheels 解决方案对我有用,谢谢。

标签: regex perl


【解决方案1】:

如果您使用的是旧版本的 Perl,那么这可能是一个因素。无论如何,我建议你做一个小的修改......

$_ =~ s/"[^\s"]+"/"$delimiter"/;

...这是一个“,一个或多个NOT空格或”,然后是一个“

【讨论】:

  • 这将匹配行5 SQLCHAR 0 1 "\n" 5 "",这不是想要的结果
  • Tardis,也许您对问题的看法不同?请用一个例子来支持你的“将匹配”声明。我的跟随...
【解决方案2】:

C:\Users\Ken>输入 test.pl

#!C:\Strawberry\perl\bin\perl -w
$\="\n";
my $d="**";
my $L1="5 SQLCHAR 0 1 \",,,\" 5 \"\"";
my $L2="5 SQLCHAR 0 1 \"\n\" 5 \"\"";
foreach my $L ($L1,$L2)
{
  print "LineIn=$L";
  if ($L=~ s/"[^\s"]+"/"$d"/) {print "#YES L=$L";}
  else {print "#NO  L=$L";}
}

C:\Users\Ken>test.pl

LineIn=5 SQLCHAR 0 1 ",,," 5 ""
#YES L=5 SQLCHAR 0 1 "**" 5 ""
LineIn=5 SQLCHAR 0 1 "
" 5 ""
#NO  L=5 SQLCHAR 0 1 "
" 5 ""

【讨论】:

  • 您的示例程序是错误的,因为您尝试使用 Perl 变量来定义数据集。OP 的数据集在 Perl 正在读取的文件中,该文件包含“ \n" 在第 5 行的第 4 列中,因此在读取此文件时,获得的字符串将包含一个斜杠和一个 n,而不是回车。
  • @argun 我可能读错了你的问题。当您声明:即“,,”和“,,,”和“,”时,除了换行符,即“\n” 是 \n 单个字符还是两个字符?谢谢!
  • @arjun,那么您的问题似乎正如我所理解的那样,您可能有兴趣签出my answer,看看是否满足您的需求。您提供某种反馈会很好,因为您的问题确实让这里的许多贡献者感到困惑,而且您只是非常谨慎地分发信息。我建议您更新您的问题以包含已传播的信息位,以便表达更清晰的要求。
【解决方案3】:

由于 OP 在他的评论中说第 4 列的内容可以是“非空白字符的任何组合”,并且他声明他不希望在第 4 列包含“\ n" 从字面上看,我建议他匹配第 4 列的内容,然后分两步测试引号中的内容是否包含 Perl 将理解为空格的 literal 表示。

为此,我们可以使用eval 或者我们可以使用带有ee modifier 的正则表达式,这样更好更安全。

这是使用后者的示例(更新 - 数据集正确包含 OP 和其他案例):

#!/usr/bin/perl

use strict;
use warnings;

my $delimiter="**";

while (<DATA>) {
    # we capture the contents of the quotes in
    # 4th column, checking also the expected format
    if (/(^([^\s]+\s+){4})"([^"]+)"(.*)/) {
        my $st = $3;
        # "\n" in the file is actually "\\n" for Perl
        # so, to have Perl understand it as "\n", we need
        # to have Perl effectively escape it, we can
        # do that with a regexp and the ee modifier
        $st =~ s/\\([tnfr])/"qq{\\$1}"/gee;
        # now this will match an "\n", "\r", "\f" or "\t"
        if (!($st =~ /\s/)) {
            print "$1\"$delimiter\"$4\n";
        } else {
            print $_;
        }
    } else {
        print "error: wrong line format: $_\n";
    }
}

__DATA__
1       SQLCHAR             0       5       ",,,"      1     ""
2       SQLCHAR             0       25      ",,,,"      2     ""
3       SQLCHAR             0       1       ","      3     ""
4       SQLCHAR             0       12      ","      4     ""
5       SQLCHAR             0       1       "\n"     5     ""
6       SQLCHAR             0       8       "a b"     6     ""
7       SQLCHAR             0       8       "\t"     7     ""
8       SQLCHAR             0       9       "\"     8     ""
9       SQLCHAR             0       9       "stuff\"     8     ""

这会导致:

1       SQLCHAR             0       5       "**"      1     ""
2       SQLCHAR             0       25      "**"      2     ""
3       SQLCHAR             0       1       "**"      3     ""
4       SQLCHAR             0       12      "**"      4     ""
5       SQLCHAR             0       1       "\n"     5     ""
6       SQLCHAR             0       8       "a b"     6     ""
7       SQLCHAR             0       8       "\t"     7     ""
8       SQLCHAR             0       9       "**"     8     ""
9       SQLCHAR             0       9       "**"     8     ""

请注意,没有简单的方法可以确定在给定环境中运行的给定脚本可以理解为“Perl whitespace”,因为它取决于许多因素,而[\t\n\f\r ] 只是一个简化视图Perl 可以理解为空格。

引用一点perlrecharclass

空格

\s 匹配任何被视为空白的单个字符。

如果 /a 修饰符生效 ...

在所有 Perl 版本中,\s 匹配 5 个字符 [\t\n\f\r ];即水平制表符、换行符、换页符、回车 返回,和空间。从 Perl v5.18 开始,它还匹配 垂直制表符 \cK 。有关此问题的讨论,请参见下面的注释 1。 否则...

对于 255 以上的代码点 ...

\s 与下表中带有“s”列的 255 以上的代码点完全匹配。

对于低于 256 的代码点 ...

如果区域设置规则生效...

\s 匹配区域设置认为是空白的任何内容。 (...)

【讨论】:

    猜你喜欢
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-15
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多