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

Matching Dollar Sign in Perl String

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 .65 New Offering|Half pound Vanilla Cake||Cake with vanilla, cream and cheese

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

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

$arr[0] 得到 Vanilla Cake .65,$arr1 得到 Half pound Vanilla Cake,$arr[2] 保持 empty/NULL,$arr[3] 得到 Cake with vanilla, cream and cheese

现在我检查 $arr[0] 是否包含价格值。要匹配的模式是一些文本 (Vanilla Cake ),然后是美元符号 ($),后跟一个或多个数字(在本例中为 3 的值),小数点是可选的 - 可能存在或可能存在不存在,然后小数点后可以有一位或多位数字(在这种情况下为.65)。 使用以下正则表达式:

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

问题是 $1、$2、$3、$4 - 所有匹配的模式值都打印为 NULL/EMPTY。 我想这是因为 $ 符号是字符串 $arr[0].

的一部分

我的猜测是,由于 $3.65 的价值,它将 $3 部分(小数点前)作为变量并尝试替换它,而 $3 为 NULL。所以正则表达式匹配正在发生购买值提取可能会失败,因为整个字符串可能被解释为 Vanilla Cake .65,而不是 Vanilla Cake .65(这是我的猜测)

可能这就是正则表达式匹配和提取失败的原因。

我还在某处读到它可能依赖于变量初始化($line$arr[0] 作为单引号或双引号) - 我不知道这种依赖性(这就是为什么包括在内所有代码都像上面 $line 变量的初始化)。 $line 一次从文件中读取一条记录,因此需要在每次迭代时进行初始化。

已尝试 Escape a dollar sign inside a variable and Trouble escaping dollar sign in Perl 中给出的解决方案,但无法使其正常工作。 在 https://regex101.com/r/FQjcHp/2/ 上创建正则表达式的其他试验和错误也无济于事。

有人可以告诉我如何使用正确的正则表达式代码从上面的字符串中获取 Vanilla Cake.65 的值吗?

PS:使用相同的代码添加在线编译器 运行 的屏幕截图,它工作正常并正确捕获 $ 值。不知何故,在我的程序中它没有接收到它。

这个代码

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

有了这个输入

Vanilla Cake .65 

将打印

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

如果您没有启用 use warnings,警告将是无声的。

这就是您提供的代码对此输入的处理方式。您还表明它与您的屏幕截图有关。您在评论中说,它不会在您的家用 PC 上执行此操作。我会说那是不可能的。

您的代码不同,您的输入不同,或者您的 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>).
  • 打印语句中的
  • </code> 和 <code> 永远不能保存值,因为您缺少必要的捕获组 ( ... ) 。两个捕获组意味着只会填充 </code> 和 <code>

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 " is ";
    }
}

__DATA__
Vanilla Cake .65 New Offering|Half pound Vanilla Cake||Cake with vanilla, cream and cheese

我 运行 大约 2 年前遇到过类似的问题 - 并且不得不打破我的头脑超过 5 天才能找到问题的根源与伟大的 $ 标志。 这是怎么回事:

未打印美元正则表达式值 - 与您观察到的类似。

很久以前有人写的 perl 代码用双引号初始化了字符串 var。像

$string="This is some text";

在我触摸它之前,它工作得很好。 :-)

我所做的是在其中插入一个变量,例如

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

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

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

它要么给出编译错误,要么无法使用我尝试过的不同正则表达式组合完全获取美元符号。

所以我的 answer-cum-suggestion 是检查您的“冗长代码”,如果您的变量上的双引号出现类似的情况。最有可能的是,这可能是导致问题的原因。

在从源头获取值之前,如果可能,请尝试在 $ 符号上使用 \,例如(至少这解决了我的问题)。 而不是

PriceVariableHavingDollarSign = "Cake is .5";

尝试

$PriceVariableHavingDollarSign ="Cake is $3.5";

这里很好地解释了 Perl 中双引号和单引号的作用。 https://www.effectiveperlprogramming.com/2012/01/understand-the-order-of-operations-in-double-quoted-contexts/

您在问题、评论和图片中提供的明确细节做得很好。它可以帮助您获得所有可能的角度、场景和解决方案。