当前位置: 首页 > 知识库问答 >
问题:

Perl:使用拆分但忽略引号

裴星洲
2023-03-14

我试图从一个输入字符串创建一个Perl哈希,但我对原始的“split”有问题,因为值可能包含引号。下面是一个输入字符串示例,以及我的(期望的)结果哈希:

my $command = 'CREATE:USER:TEL,12345678:MOB,444001122:Type,Whatever:ATTRIBUTES,"ID,0,MOB,123,KEY,VALUE":TIME,"08:01:59":FIN,0';

my %hash = 
  (
   CREATE     => '',
   USER       => '',
   TEL        => '12345678',
   MOB        => '444001122',
   Type       => 'Whatever',
   ATTRIBUTES => 'ID,0,MOB,123,KEY,VALUE',
   TIME       => '08:01:59',
   FIN        => '0',
  );

输入字符串的长度是任意的,并且没有设置键的数量。

谢谢!

-总部

共有3个答案

狄玉书
2023-03-14

这似乎是Text::ParseWords可以处理的。quotewords子例程将分割分隔符上的输入,忽略引号内的分隔符。这将为我们提供项目的基本列表,首先在输出中显示为$VAR1。之后,只需使用正则表达式解析逗号分隔的项,正则表达式将处理可选的第二次捕获,以容纳空标记,例如CREATEUSER的标记。

use strict;
use warnings;
use Data::Dumper;
use Text::ParseWords;

while (<DATA>) {
    chomp;
    my @list = quotewords(':', 0, $_);
    my %hash = map { my ($k, $v) = /([^,]+),?(.*)/; $k => $v; } @list;
    print Dumper \@list, \%hash;
}

__DATA__
CREATE:USER:TEL,12345678:MOB,444001122:Type,Whatever:ATTRIBUTES,"ID,0,KEY,VALUE":TIME,"08:01:59":FIN,0

输出:

$VAR1 = [
          'CREATE',
          'USER',
          'TEL,12345678',
          'MOB,444001122',
          'Type,Whatever',
          'ATTRIBUTES,ID,0,KEY,VALUE',
          'TIME,08:01:59',
          'FIN,0'
        ];
$VAR2 = {
          'TIME' => '08:01:59',
          'MOB' => '444001122',
          'Type' => 'Whatever',
          'CREATE' => '',
          'TEL' => '12345678',
          'ATTRIBUTES' => 'ID,0,KEY,VALUE',
          'USER' => '',
          'FIN' => '0'
        };
郭璞
2023-03-14

据我所知,最明显的候选者——Text::CSV——无法正确处理这种格式,因此只有一种自制的正则表达式解决方案

use strict;
use warnings;

my $command = 'CREATE:USER:TEL,12345678:MOB,444001122:Type,Whatever:ATTRIBUTES,"ID,0,KEY,VALUE":TIME,"08:01:59":FIN,0';

my %config;
for my $field ($command =~ /(?:"[^"]*"|[^:])+/g) {
  my ($key, $val) = split /,/, $field, 2;
  ($config{$key} = $val // '') =~ s/"([^"]*)"/$1/;
}

use Data::Dumper;
print Data::Dumper->Dump([\%config], ['*config']);

输出

%config = (
            'TIME' => '08:01:59',
            'MOB' => '444001122',
            'Type' => 'Whatever',
            'CREATE' => '',
            'TEL' => '12345678',
            'ATTRIBUTES' => 'ID,0,KEY,VALUE',
            'USER' => '',
            'FIN' => '0'
          );

如果你有Perl v5。10或更高版本之后,您就有了方便的(?|…) 正则表达式组,它允许您编写

use 5.010;
use warnings;

my $command = 'CREATE:USER:TEL,12345678:MOB,444001122:Type,Whatever:ATTRIBUTES,"ID,0,KEY,VALUE":TIME,"08:01:59":FIN,0';

my %config = $command =~ /(\w+) (?| , " ([^"]*) " | , ([^:"]*) | () )/gx;

use Data::Dumper;
print Data::Dumper->Dump([\%config], ['*config']);

这将产生与上面代码相同的结果。

马银龙
2023-03-14

使用Text::CSV。它可以正确处理逗号分隔的值文件

标准模块似乎无法解析您输入的格式,即使使用sep_charallow_loose_quotes。因此,您必须自己完成繁重的工作,但仍然可以使用Text::CSV解析每个键值对:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw(say);

use Data::Dumper;

use Text::CSV;

my $command = 'CREATE:USER:TEL,12345678:MOB,444001122:Type,Whatever:ATTRIBUTES,"ID,0,KEY,VALUE":TIME,"08:01:59":FIN,0';

my @fields = split /:/, $command;
my %hash;
my $csv = Text::CSV->new();

my $i = 0;
while ($i <= $#fields) {
    if (1 == $fields[$i] =~ y/"//) {
        my $j = $i;
        $fields[$i] .= ':' . $fields[$j] until 1 == $fields[++$j] =~ y/"//;
        $fields[$i] .= ':' . $fields[$j];
        splice @fields, $i + 1, $j - $i, ();
    }
    $csv->parse($fields[$i]);
    my ($key, $value) = $csv->fields;
    $hash{$key} = "$value"; # quotes turn undef to q()
    $i++;
}

print Dumper \%hash;
 类似资料:
  • 我收到了很多文件,其中我的控制为零,我需要根据分隔符进行拆分。但是当分隔符在引号内时,我不想拆分。因此,列 1、列 2、列 3 是 然而,column1、“column2”、column3是 这可以使用此正则表达式(在 C# 下) 现在,我的问题是当有一行只有一个双引号(仅打开或关闭)时,例如第1列,第2列",第3列返回 虽然它应该返回 我发现很多与正则表达式相关的,但在上面的特定示例中,它们都失

  • 问题内容: 仅使用正则表达式方法,方法String.replaceAll和ArrayList如何将字符串拆分为标记,但忽略引号内存在的定界符?分隔符是非字母数字或带引号的文本的任何字符 例如:字符串: 你好^世界’这*有两个令牌’ 应该输出: 你好 worldthis *有两个令牌 问题答案: 使用a 来标识要保留的部分,而不是要拆分的部分: 看到它在线上工作:ideone

  • 问题内容: 我的文字如下: 谁能告诉我我必须使用哪些正则表达式分度数才能获得以下结果: 我在这里阅读Sun教程,直到“ Matcher类的方法”为止,但我仍然茫然。谢谢! 如果是这样,那将很容易,但是不幸的是,事实并非如此。有任何想法吗? 问题答案: 您可以直接使用split()方法,如下所示: (请注意,这将返回长度为5的数组,第一个位置为空字符串) 或者,如果您想使用模式/匹配器,可以这样做:

  • 问题内容: 我正在寻找将其转换为6个元素的数组:a,b,c,“ d,e,f”,g,h。我正在尝试通过Javascript执行此操作。这是我到目前为止所拥有的: 但是现在,它会将双引号中的所有内容都分割开了,这是不正确的。 编辑:好的,抱歉,我对这个问题的措辞很差。给我一个字符串而不是数组。 我想使用“ split”功能将 其 转换为数组。 问题答案: 这就是我要做的。

  • 问题内容: 我已经看到了许多相关的问题,但是都没有直接解决我想做的事情。我正在从CSV文件中读取文本行。 所有项目都用引号引起来,有些则在引号内有其他逗号。我想按逗号分隔行,但忽略引号内的逗号。有没有一种方法可以在Python中执行此操作,而无需使用许多正则表达式语句。 一个例子是: 我想将其解析为4个单独的值变量: 我想念一个简单的选择吗? 问题答案: 不要尝试重新发明轮子。 如果要读取CSV文

  • 输入字符串用逗号分隔。但它可能包含双引号内的逗号,需要忽略。下面是示例字符串 下面是我用来拆分逗号的代码,但如果逗号是双引号中字符串的一部分,它就会失败。 所以任何解决这个问题的想法。