【发布时间】:2012-03-16 10:00:34
【问题描述】:
如果我有
$t = '20110512102331';
并且只想要来自$t 的前 4 个字符。
我该怎么做?
【问题讨论】:
-
你问了 很多 Perl 问题,通常是非常基本的问题。您现在还没有学会自己搜索文档吗?为什么不呢?
-
根据您的历史,我认为我的书Learning Perl 会有所帮助。 :)
标签: perl
如果我有
$t = '20110512102331';
并且只想要来自$t 的前 4 个字符。
我该怎么做?
【问题讨论】:
标签: perl
通过像这样使用substr 函数 -
my $t = "20110512102331";
my $four = substr($t, 0, 4)
【讨论】:
对于您的特定问题,从字符串中提取似乎是年份,substr 意外工作,但这里确实是错误的答案。它的“性格”观念不是我们的“性格”观念。注意résumé 的不同归一化形式如何产生不同的结果。您可能需要前四个字素,可以与 \X 匹配(尽管在 ASCII 中字素和字符给出相同的结果)
use v5.10.1;
use utf8;
use strict;
use warnings;
use Unicode::Normalize qw(NFD NFC);
my $string = '20110512102331';
say "$string → ", substr $string, 0, 4;
my $ustring = NFD( 'résumé' );
say "NFD $ustring → ", substr $ustring, 0, 4;
$ustring = NFC( 'résumé' );
say "NFC $ustring → ", substr $ustring, 0, 4;
$ustring = NFD( 'résumé' );
say "\\X with NFD $ustring → ", $ustring =~ m/(\X{4})/;
$ustring = NFC( 'résumé' );
say "\\X with NFC $ustring → ", $ustring =~ m/(\X{4})/;
注意 NFD 结果不同:
$ perl -C substr.pl
20110512102331 → 2011
NFD résumé → rés
NFC résumé → résu
\X with NFD résumé → résu
\X with NFC résumé → résu
不过,substr 确实有一些 Unicode 功夫,如果你给它一个来自 Unicode::GCString 的字符串:
use v5.10.1;
use utf8;
use strict;
use warnings;
use Unicode::GCString;
use Unicode::Normalize qw(NFD);
my $gcstring = Unicode::GCString->new( NFD('résumé') );
say "$gcstring → ", $gcstring->substr( 0, 4 );
这会得到正确的结果:
$ perl -C gcsubstr.pl
résumé → résu
但是,所有这些都解决了字符串不仅仅是字符集合的问题。这些字符具有特殊含义,因此您可以使用该特殊含义来做正确的事情,而无需考虑字符串操作。如果您可以描述格式,DateTime::Format::Strptime 是解析任意日期格式的好方法:
use v5.10.1;
use utf8;
use strict;
use warnings;
use DateTime::Format::Strptime;
my $Strp = DateTime::Format::Strptime->new(
pattern => '%Y%m%d%H%M%S',
);
my $Strf = DateTime::Format::Strptime->new(
pattern => '%Y',
);
my $dt = $Strp->parse_datetime('20110512102331');
my $year = $Strf->format_datetime($dt);
say "year is $year";
您可能还想查看How can I parse dates and convert time zones in Perl?。
无论您决定采用何种方式,您都可以将实现细节隐藏在子例程中,这样您就可以在不中断程序其余部分的情况下对其进行更改。
【讨论】:
最简单:使用substr函数:
my $firstfour = substr($t,0,4);
另一种方法是使用正则表达式:
my $firstfour = ($t =~ /(.{0,4}).*/s ? $1 : $t);
或者,更短的,通过在列表上下文中调用正则表达式:
my ($firstfour) = $t =~ /(.{0,4})/s;
【讨论】:
m/(.{4})/ms 更适合“字符串的前四个字符”。当然存在长度小于 4 的字符串的极端情况。标准假设是返回与字符串一样多的字符。所以我们可以在这种情况下做到这一点:m/(.{1,4})/ms.
$firstfour 未定义。 /m 限定符在这里也无关紧要。 /(.{0,4})/s 是正确的。
$t='20110512102331';
print substr($t, 0, 4);
更多信息请参见perldoc -f substr。
【讨论】: