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

标签 regex perl

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 蛋糕 $3.65,$arr 1获取半磅 Vanilla 蛋糕,$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 $1, match2 is $2, match3 is $3, match4 is $4\n";
}

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

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

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

我还在某处读到它可能依赖于变量初始化($line$arr[0] 作为单引号或双引号)——我没有关于这种依赖关系的线索(这就是为什么包括所有代码,如上面 $line 变量的初始化)。 $line 一次从文件中读取一条记录,因此需要在每次迭代时初始化。

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

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

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

最佳答案

这段代码

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,警告将是无声的启用。

这是您提供的代码对此输入的处理方式。您还表明它与您的屏幕截图有关。您在评论中说,它不会在您的家用 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>) .
  • $3$4在您的 print 语句中永远无法保存值,因为您缺少捕获组 ( ... )必要的。两个捕获组仅表示 $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

关于regex - 在 Perl 字符串中匹配美元符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72363022/

相关文章:

javascript - 使用 RegExp 在模式中查找模式的多个实例

c# - 删除字符串中的特殊字符和无效字符

regex - Bash 正则表达式在行开头匹配 "./"?或者使用前导 "-"重命名文件

Java 正则表达式匹配拉丁字母对应字符的变音符号

perl 一行只保留所需的行

javascript - 简化 JavaScript 正则表达式

perl - XML::Simple 删除根元素

perl - 如何有条件地从另一个模块导入函数并将它们导出到本地命名空间

linux - 将主脚本变量传递到 Perl 模块

perl - df 输出问题