Perl字符串中的匹配美元符号

ulydmbyx  于 2022-11-15  发布在  Perl
关注(0)|答案(2)|浏览(129)

Perl程序中包含美元($)符号的简单文本字符串:

open my $fh, "<", $fp or die "can't read open '$fp': $OS_ERROR";
  while (<$fh>)
  {
    $line=''; #Initialize the line variable
    $line=$_; #Reading a record from a text file
    print "Line is $line\n"; #Printing for confirming
    (@arr)=split('\|',$line);

$line获取以下以竖线分隔的字符串(通过打印$line值进行确认):

Vanilla Cake $3.65 New Offering|Half pound Vanilla Cake||Cake with vanilla, cream and cheese

然后将记录拆分并拉入特定数组元素:

(@arr)=split('\|',$line);

$arr[0]获取Vanilla Cake $3.65,$arr 1获取Half pound Vanilla Cake,$arr[2]仍为empty/NULL,$arr[3]获取Cake with vanilla, cream and cheese
现在我检查$arr[0]是否包含价格值。要匹配的模式是一些文本(Vanilla Cake),然后是一个美元符号($),后面是一个或多个数字(本例中的值为3),decimal是可选的-可能存在也可能不存在,然后在decimal后面可以有一个或多个数字(本例中为.65)。使用以下正则表达式:

if ($arr[0]=~ /(.*?)(\$\d+(?:\.\d+)?)/)
{
     print "match1 is $1, match2 is $2, match3 is $3, match4 is $4\n";
}

问题是$1,$2,$3,$4 -所有匹配的模式值都打印为NULL/EMPTY。我想这是因为$符号是字符串$arr[0]的一部分。
我的猜测是,因为$3.65值,它将$3部分(小数点前)作为变量,并试图替换它,而$3为NULL。因此,正则表达式匹配正在发生,但值提取可能失败,因为整个字符串可能被解释为Vanilla Cake .65,而不是Vanilla Cake $3.65(这是我的猜测)
可能,这就是正则表达式匹配和提取失败的原因。
我还读到它可能依赖于变量的初始化($line$arr[0]作为单引号或双引号)-我不知道这样的依赖性(这就是为什么包括所有的代码,如上面的$line变量的初始化)。$line从一个文件中一次读取一个记录,所以需要在每次迭代初始化。
已经尝试了Escape a dollar sign inside a variableTrouble escaping dollar sign in Perl中给出的解决方案,但无法让它工作。在https://regex101.com/r/FQjcHp/2/上创建regex的其他尝试和错误也没有帮助。
有人能告诉我如何使用正确的正则表达式代码从上面的字符串中得到Vanilla Cake$3.65的值吗?
PS:添加了一个在线编译器运行相同代码的截图,它工作正常,并正确捕获$ value。不知何故,在我的程序中,它没有拾取它。x1c 0d1x

j91ykkif

j91ykkif1#

此代码

if ($foo =~ /(.*?)(\$\d+(?:\.\d+)?)/) {
     print "match1 is $1, match2 is $2, match3 is $3, match4 is $4\n";
}

有了这个输入

Vanilla Cake $3.65

将打印

Use of uninitialized value $3 in concatenation (.) or string at ...
Use of uninitialized value $4 in concatenation (.) or string at ...
match1 is Vanilla Cake , match2 is $3.65, match3 is , match4 is

如果未启用use warnings,则警告将不显示。
这就是你提供的代码对这个输入所做的。你也展示了它对你的屏幕截图所做的。你在评论中说,它在你的家用电脑上不做这个。我会说这是不可能的。
要么是代码不同,要么是输入不同,要么是Perl安装不同(尽管这不太可能是问题所在)。
一个很大的问题是你没有在代码中使用use strict; use warnings。这意味着你的代码中隐藏了很多问题。最有可能的是,在你的情况下,我会说这是一个打字错误,例如:

$Iine = $_;
if ($line =~ /...../)  # <---- not the same variable

但是你要求8个小时来更新你的代码,所以我猜我们会在8个小时内找到答案。
几点提示

while (<$fh>)
  {
    $line=''; #Initialize the line variable
    $line=$_; #Reading a record from a text file
  • 您不需要“初始化”行变量。下一行将使该行完全冗余。
  • 这一行实际上并没有从文件中阅读记录,而是由readline语句<$fh>来完成。
  • 通常您会将此行写成:while (my $line = <$fh>) .
  • print语句中的$3$4永远不能保存值,因为缺少必需的捕获组( ... )。两个捕获组意味着将只填充$1$2

When writing Perl code, you should always use

use strict;
use warnings;

因为不这样做对你没有帮助,只会掩盖你的问题。
还要养成将声明(my $var)放在尽可能小的范围内的习惯。示例代码:

use strict;
use warnings;
use feature 'say';

while (my $line = <DATA>) {
    my @x = split /\|/, $line;
    if ($x[0] =~ /(.*?)(\$\d+(?:\.\d+)?)/) {
        say "$1 is $2";
    }
}

__DATA__
Vanilla Cake $3.65 New Offering|Half pound Vanilla Cake||Cake with vanilla, cream and cheese
cnwbcb6i

cnwbcb6i2#

大约两年前,我也遇到过类似的问题-I我花了5天多的时间才弄清楚这个问题的根源,因为我的$符号太大了。
美元正则表达式值没有打印-类似于你所观察到的。
很久以前有人编写的Perl代码用双引号初始化了字符串var。

$string="This is some text";

而且它工作得很完美,直到我碰了它。:-)
我所做的就是在里面插入一个变量

$string="This is some $PriceVariableHavingDollarSign text";

然后我尝试在$string变量上运行一个美元匹配正则表达式,希望能检测到美元。不完全是,但与您尝试做的非常相似,如下所示:

$string=~ /(.*?)(\$\d+(?:\.\d+)?)/

而且它要么给出了编译错误,要么没能用我尝试过的不同regex组合完全拾取美元符号。
因此,我的回答和建议是检查你的“冗长代码”,如果类似的事情发生在你的变量的双引号上,最有可能的是,这可能是造成问题。
在从源代码中获取值之前,如果可能的话,尝试在$符号上使用\,例如(至少这解决了我的问题)。

PriceVariableHavingDollarSign = "Cake is $3.5";

试着拥有

$PriceVariableHavingDollarSign ="Cake is \$3.5";

下面是对Perl中双引号和单引号的详细解释。https://www.effectiveperlprogramming.com/2012/01/understand-the-order-of-operations-in-double-quoted-contexts/
你在问题、评论和图片中加入了明确的细节,这是一个很好的工作。它可以帮助你获得所有可能的Angular 、场景和解决方案。

相关问题