如果您保证有格式良好的数据,只包含 DD-MM-YYYY 格式的单例日期,那么这样可以:
# FIRST METHOD
my $ndate = join("-" => reverse split(m[/], $date));
这适用于持有“07/04/1776”的$date,但在“这个 17/01/2010 和那个 01/17/2010 那里”失败。相反,使用:
# SECOND METHOD
($ndate = $date) =~ s{
\b
( \d \d )
/ ( \d \d )
/ ( \d {4} )
\b
}{$3-$2-$1}gx;
如果您喜欢更“语法”的正则表达式,以便更容易维护和更新,您可以改用这个:
# THIRD METHOD
($ndate = $date) =~ s{
(?&break)
(?<DAY> (?&day) )
(?&slash) (?<MONTH> (?&month) )
(?&slash) (?<YEAR> (?&year) )
(?&break)
(?(DEFINE)
(?<break> \b )
(?<slash> / )
(?<year> \d {4} )
(?<month> \d {2} )
(?<day> \d {2} )
)
}{
join "-" => @+{qw<YEAR MONTH DAY>}
}gxe;
最后,如果您有 Unicode 数据,您可能需要更加小心。
# FOURTH METHOD
($ndate = $date) =~ s{
(?&break_before)
(?<DAY> (?&day) )
(?&slash) (?<MONTH> (?&month) )
(?&slash) (?<YEAR> (?&year) )
(?&break_after)
(?(DEFINE)
(?<slash> / )
(?<start> \A )
(?<finish> \z )
# don't really want to use \D or [^0-9] here:
(?<break_before>
(?<= [\pC\pP\pS\p{Space}] )
| (?<= \A )
)
(?<break_after>
(?= [\pC\pP\pS\p{Space}]
| \z
)
)
(?<digit> \d )
(?<year> (?&digit) {4} )
(?<month> (?&digit) {2} )
(?<day> (?&digit) {2} )
)
}{
join "-" => @+{qw<YEAR MONTH DAY>}
}gxe;
您可以看到这四种方法中的每一种在遇到如下示例输入字符串时的表现:
my $sample = q(17/01/2010);
my @strings = (
$sample, # trivial case
# multiple case
"this $sample and that $sample there",
# multiple case with non-ASCII BMP code points
# U+201C and U+201D are LEFT and RIGHT DOUBLE QUOTATION MARK
"from \x{201c}$sample\x{201d} through\xA0$sample",
# multiple case with non-ASCII code points
# from both the BMP and the SMP
# code point U+02013 is EN DASH, props \pP \p{Pd}
# code point U+10179 is GREEK YEAR SIGN, props \pS \p{So}
# code point U+110BD is KAITHI NUMBER SIGN, props \pC \p{Cf}
"\x{10179}$sample\x{2013}\x{110BD}$sample",
);
现在让 $date 成为 foreach 遍历该数组的迭代器,我们得到以下输出:
Original is: 17/01/2010
First method: 2010-01-17
Second method: 2010-01-17
Third method: 2010-01-17
Fourth method: 2010-01-17
Original is: this 17/01/2010 and that 17/01/2010 there
First method: 2010 there-01-2010 and that 17-01-this 17
Second method: this 2010-01-17 and that 2010-01-17 there
Third method: this 2010-01-17 and that 2010-01-17 there
Fourth method: this 2010-01-17 and that 2010-01-17 there
Original is: from “17/01/2010” through 17/01/2010
First method: 2010-01-2010” through 17-01-from “17
Second method: from “2010-01-17” through 2010-01-17
Third method: from “2010-01-17” through 2010-01-17
Fourth method: from “2010-01-17” through 2010-01-17
Original is: ?17/01/2010–?17/01/2010
First method: 2010-01-2010–?17-01-?17
Second method: ?2010-01-17–?2010-01-17
Third method: ?2010-01-17–?2010-01-17
Fourth method: ?2010-01-17–?2010-01-17
现在让我们假设您确实确实想要匹配非 ASCII 数字。例如:
U+660 ARABIC-INDIC DIGIT ZERO
U+661 ARABIC-INDIC DIGIT ONE
U+662 ARABIC-INDIC DIGIT TWO
U+663 ARABIC-INDIC DIGIT THREE
U+664 ARABIC-INDIC DIGIT FOUR
U+665 ARABIC-INDIC DIGIT FIVE
U+666 ARABIC-INDIC DIGIT SIX
U+667 ARABIC-INDIC DIGIT SEVEN
U+668 ARABIC-INDIC DIGIT EIGHT
U+669 ARABIC-INDIC DIGIT NINE
甚至
U+1D7F6 MATHEMATICAL MONOSPACE DIGIT ZERO
U+1D7F7 MATHEMATICAL MONOSPACE DIGIT ONE
U+1D7F8 MATHEMATICAL MONOSPACE DIGIT TWO
U+1D7F9 MATHEMATICAL MONOSPACE DIGIT THREE
U+1D7FA MATHEMATICAL MONOSPACE DIGIT FOUR
U+1D7FB MATHEMATICAL MONOSPACE DIGIT FIVE
U+1D7FC MATHEMATICAL MONOSPACE DIGIT SIX
U+1D7FD MATHEMATICAL MONOSPACE DIGIT SEVEN
U+1D7FE MATHEMATICAL MONOSPACE DIGIT EIGHT
U+1D7FF MATHEMATICAL MONOSPACE DIGIT NINE
所以假设你有一个数学等宽数字的日期,像这样:
$date = "\x{1D7F7}\x{1D7FD}/\x{1D7F7}\x{1D7F6}/\x{1D7F8}\x{1D7F6}\x{1D7F7}\x{1D7F6}";
Perl 代码可以正常工作:
Original is: ??/??/????
First method: ????-??-??
Second method: ????-??-??
Third method: ????-??-??
Fourth method: ????-??-??
我想你会发现 Python 有一个相当脑残的 Unicode 模型,它缺乏对抽象字符和字符串(无论内容如何)的支持,这使得编写这样的东西非常困难。
在 Python 中编写清晰的正则表达式也很困难,因为您将子表达式的声明与其执行分离,因为那里不支持 (?(DEFINE)...) 块。哎呀,Python 甚至不支持 Unicode 属性。因此,它不适合 Unicode 正则表达式工作。
但是,嘿,如果你认为 Python 与 Perl 相比不好(确实是),那就试试其他任何语言吧。我还没有找到更适合这种工作的。
如您所见,当您要求来自多种语言的正则表达式解决方案时,您会遇到真正的问题。首先,由于正则表达式风格不同,解决方案难以比较。但也因为没有其他语言可以与 Perl 相比,其正则表达式的功能、表现力和可维护性。一旦任意 Unicode 进入图片,这可能会变得更加明显。
因此,如果您只想要 Python,那么您应该只要求它。否则,这是一场非常不公平的比赛,Python 几乎总是会输。在 Python 中正确处理这样的事情实在是太麻烦了,更不用说 both 正确和干净了。这要求比它所能产生的要多。
相比之下,Perl 的正则表达式在这两个方面都表现出色。