Regex Perl中带条件替换的正则表达式替换

Regex Perl中带条件替换的正则表达式替换,regex,perl,Regex,Perl,我的Perl技能相当初级,我正在尝试使用正则表达式替换(除其他外)将加载在标量变量中的数据文件中的日期转换为四位数的年份 我需要做以下工作,以便在所有年份中增加20 $data00 =~ s/^D(\d{2})\/(\d{2})\/(\d{2})\n/D$1\/$2\/20$3\n/gm; 但是,这些日期包括2000年之前的日期 在搜索解决方案时,我运行了/e选项,该选项表示它将替换作为Perl代码进行评估。但是,我没有在我遇到的所有文档中找到它,我也不确定它的语法是什么 有没有办法评估3美元

我的Perl技能相当初级,我正在尝试使用正则表达式替换(除其他外)将加载在标量变量中的数据文件中的日期转换为四位数的年份

我需要做以下工作,以便在所有年份中增加20

$data00 =~ s/^D(\d{2})\/(\d{2})\/(\d{2})\n/D$1\/$2\/20$3\n/gm;
但是,这些日期包括2000年之前的日期

在搜索解决方案时,我运行了/e选项,该选项表示它将替换作为Perl代码进行评估。但是,我没有在我遇到的所有文档中找到它,我也不确定它的语法是什么

有没有办法评估3美元的匹配,如果3美元少于50美元,输出20美元,2000年输出,如果不是,输出19美元,1997年输出?我选择了50,因为这似乎是一个安全的中间地带

为了便于说明,尽管我知道这是不正确的:

$data00 =~ s/^D(\d{2})\/(\d{2})\/(\d{2})\n/D$1\/$2\/(if($3<50)20 else 19)$3\n/eg;

使用
/e
时,替换表达式必须是有效的Perl表达式(即,可以在
$x=
后面放置的内容)

您可以使用条件运算符(
?:
)根据条件对表达式进行不同的求值:

s/^D(\d{2})\/(\d{2})\/(\d{2})\n/ "D$1\/$2\/".( $3 < 50 ? 20 : 19 )."$3\n" /eg

使用
/e
时,替换表达式必须是有效的Perl表达式(即,可以在
$x=
后面放置的内容)

您可以使用条件运算符(
?:
)根据条件对表达式进行不同的求值:

s/^D(\d{2})\/(\d{2})\/(\d{2})\n/ "D$1\/$2\/".( $3 < 50 ? 20 : 19 )."$3\n" /eg
我过去常这样做。使用
strtime()
类方法将日期解析为对象,然后使用
strftime()
对其进行格式化

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';
use Time::Piece;

while (<DATA>) {
  chomp;

  my $date = Time::Piece->strptime($_, 'D%m/%d/%y');

  say $date->strftime('D%m/%d/%Y');
}

__DATA__
D04/07/97
D04/14/98
D10/06/99
D10/13/05
D03/04/10
D12/09/10
D01/20/11
D12/22/11
regex解决方案可以通过a)选择不同的分隔符和b)使用三元运算符来简化。如果使用
/e
,则替换文本需要在语法上有效

while (<DATA>) {
  chomp;

  s|D(\d{2}/\d{2}/)(\d{2})|"D$1" . ($2 < 50 ? '20' : '19') . $2|e;

  say;
}
while(){
咀嚼;
s|D(\D{2}/\D{2}/)(\D{2})|“D$1”。($2<50?'20':'19')。$2|e;
说,;
}
更新:这两种解决方案之间有一个(可能很重要)区别——从两位数年份转换为四位数年份时,20世纪和21世纪之间的界限。正则表达式解决方案使用50(如原始问题中所述)。Time::Piece解决方案使用69-并且该限制是硬编码的,因此无法更改它。对于原始问题中的数据,这没有区别。但如果你有1950年到1969年之间的数据,这可能很重要。

我会这样做。使用
strtime()
类方法将日期解析为对象,然后使用
strftime()
对其进行格式化

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';
use Time::Piece;

while (<DATA>) {
  chomp;

  my $date = Time::Piece->strptime($_, 'D%m/%d/%y');

  say $date->strftime('D%m/%d/%Y');
}

__DATA__
D04/07/97
D04/14/98
D10/06/99
D10/13/05
D03/04/10
D12/09/10
D01/20/11
D12/22/11
regex解决方案可以通过a)选择不同的分隔符和b)使用三元运算符来简化。如果使用
/e
,则替换文本需要在语法上有效

while (<DATA>) {
  chomp;

  s|D(\d{2}/\d{2}/)(\d{2})|"D$1" . ($2 < 50 ? '20' : '19') . $2|e;

  say;
}
while(){
咀嚼;
s|D(\D{2}/\D{2}/)(\D{2})|“D$1”。($2<50?'20':'19')。$2|e;
说,;
}

更新:这两种解决方案之间有一个(可能很重要)区别——从两位数年份转换为四位数年份时,20世纪和21世纪之间的界限。正则表达式解决方案使用50(如原始问题中所述)。Time::Piece解决方案使用69-并且该限制是硬编码的,因此无法更改它。对于原始问题中的数据,这没有区别。但是如果你有1950年到1969年之间的数据,这可能很重要。

谢谢布莱辛。你的方法符合我脚本的流程。我在编写脚本,以便在最终转换和输出之前,所有数据的处理都在缩放器中完成。正如我提到的,我的Perl技能相当初级,你的解决方案我也很容易理解。@ikegami感谢你帮助我使答案更友好、更完整。该死的,我不知道enter会发布回复,继续。老实说,一开始我无法让它工作,我花了一点时间才意识到我必须在行中添加“m”选项才能让它工作。如:
$data00=~s/^D(\D{2})\/(\D{2})\/(\D{2})\n/“D$1\/$2\/”($3@tanker,
/m
更改
^
(和
$
)的定义。通常,它只匹配字符串的开头。对于
/m
,它在换行后也会匹配。感谢blhsing。您的方法符合我的脚本流程。我编写脚本时,所有数据的处理都是在最终转换和输出之前在缩放器中完成的。正如我提到的,我的Perl技能和d您的解决方案我很容易理解。@ikegami感谢您帮助我使答案更友好、更完整。该死的,我不知道enter会发布回复,继续。老实说,一开始我无法让它工作,我花了一点时间才意识到我必须在行中添加“m”选项才能工作。例如:
$data00=~s/^d(\d{2})\/(\d{2})\/(\d{2})\n/“d$1\/$2\/”($3@tanker,
/m
更改
^
(和
$
)的定义。通常,它只匹配字符串的开头。对于
/m
,它在换行后也匹配。