1

在 Perl 中,有ucfirst函数。

这是否等同于:

sub uppercase {     
    my ($W) = @_;       
    $$W = uc(substr($$W,0,1)).substr($$W,1);        
}

跨 Perl 版本是否重要?


将问题情境化,https://github.com/moses-smt/mosesdecoder/pull/206/files#diff-876e51db2a1ab71c1ae736182d1e5e04R63

以前,的用法uppercase是这样的:

sub process {
    my $line = $_[0];
    chomp($line);
    $line =~ s/^\s+//;
    $line =~ s/\s+$//;
    my @WORD  = split(/\s+/,$line);

    # uppercase at sentence start
    my $sentence_start = 1;
    for(my $i=0;$i<scalar(@WORD);$i++) {
      &uppercase(\$WORD[$i]) if $sentence_start;
      if (defined($SENTENCE_END{ $WORD[$i] })) { $sentence_start = 1; }
      elsif (!defined($DELAYED_SENTENCE_START{$WORD[$i] })) { $sentence_start = 0; }
    }

    # uppercase headlines {
    if (defined($SRC) && $HEADLINE[$sentence]) {
        foreach (@WORD) {
            &uppercase(\$_) unless $ALWAYS_LOWER{$_};
        }
    }

但它似乎替换&uppercase(\$WORD[$i])and &uppercase(\$_)with ucfirst(\$WORD[$i])anducfirst(\$_)是不同的。

4

3 回答 3

2

在 Perl 中,有 ucfirst 函数。

这是否等同于:

让我们找出...

$ cat testuc
use strict;
use warnings;
use Test::More; 

sub uppercase {
  my ($w) = @_;
  return uc(substr($w, 0, 1)) . substr($w, 1);
}

my @tests = qw[foobar Foobar FOOBar fOObar fOObAR FOOBAR];

for (@tests) {
  is(ucfirst($_), uppercase($_), "correct for $_");
}

done_testing;

$ prove -v testuc
testuc ..
ok 1 - correct for foobar
ok 2 - correct for Foobar
ok 3 - correct for FOOBar
ok 4 - correct for fOObar
ok 5 - correct for fOObAR
ok 6 - correct for FOOBAR
1..6
ok
All tests successful.
Files=1, Tests=6,  0 wallclock secs ( 0.04 usr  0.03 sys +  0.03 cusr  0.04 csys =  0.14 CPU)
Result: PASS

所以,是的,看起来它们是同一件事(至少对于我相当有限的一组测试而言)。

我正在使用 Perl 5.26.1 - 但我认为这对于至少回到 5.10 的所有 Perl 版本都可以正常工作。

更新:

我对您忘记提及的代码进行了静默编辑。您的代码最初处理对标量的引用,但我将其更改为处理标量($W而不是$$W)。我认为这将是一种无害的替代品。

但是现在你已经向我们展示了你在上下文中的变化,我可以看到发生了什么。

你有过:

&uppercase(\$WORD[$i])

您将其更改为:

ucfirst(\$WORD[$i])

这不起作用,因为ucfirst()不会改变它的论点;它返回更改后的值。所以你实际上想要:

$WORD[$i] = ucfirst($WORD[$i]);

这将按预期工作(以其他答案中提到的 Unicode 字符问题为模。

如果您远离 C 样式循环,则可以简化整个for循环。

for my $w (@WORD) {
  $w = ucfirst($w) if $sentence_start;

  if (defined $SENTENCE_END{ $w }) {
    $sentence_start = 1;
  } elsif (!defined $DELAYED_SENTENCE_START{ $w }) {
    $sentence_start = 0;
  }
}
于 2019-01-04T10:26:27.077 回答
2

ucfirst不等同于以下内容:

sub uppercase {     
    my ($W) = @_;       
    $$W = uc(substr($$W,0,1)).substr($$W,1);        
}

ucfirst大多[1]等价于以下内容:

sub ucfirst {     
    my ($W) = @_;       
    return uc(substr($W,0,1)).substr($W,1);        
}

如果你想用 来重写uppercaseucfirst它看起来像这样:

sub uppercase {     
    my ($W) = @_;
    $$W = ucfirst($$W);    
}

uppercase(\$string);

这意味着如果你想uppercase完全消除,你会替换

uppercase(\$string);

$string = ucfirst($string);     # Correct

您尝试使用

ucfirst(\$string);              # Wrong

  1. ucfirst实际上在处理更深奥的字符方面做得更好,例如 U+01F3 LATIN SMALL LETTER DZ ("dz")。
于 2019-01-04T10:50:32.150 回答
2

由于一些 Unicode 细节,特别是处理digraphs ,这些函数并不等效。

例如,匈牙利语使用有向图"DZ",它被认为是字母表中的单个字母,因此可以选择使用 Unicode 代码点表示:

  • U+01F1: DZ
  • U+01F2: 兹
  • U+01F3: dz

所以

my $text1 = "\x{1f3}won";
my $text2 = $text1;
$text1 = ucfirst($text1);
uppercase(\$text2);
print($text1 eq $text2 ? "same\n" : "different\n");

打印“不同”。

于 2019-01-04T10:57:38.470 回答