13

我有字符串"re\x{0301}sume\x{0301}"(打印如下:resume),我想将其反转为"e\x{0301}muse\x{0301}r"(émusér)。我不能使用 Perl reverse,因为它将组合字符"\x{0301}"视为单独的字符,所以我最终得到"\x{0301}emus\x{0301}er"(́emuśer)。如何反转字符串,但仍然尊重组合字符?

4

5 回答 5

12

您可以使用\X 特殊转义(匹配非组合字符和所有以下组合字符)split来制作字素列表(它们之间有空字符串),反转字素列表,然后将join它们重新组合在一起:

#!/usr/bin/perl

use strict;
use warnings;

my $original = "re\x{0301}sume\x{0301}";
my $wrong    = reverse $original;
my $right    = join '', reverse split /(\X)/, $original;
print "original: $original\n",
      "wrong:    $wrong\n",
      "right:    $right\n";
于 2009-08-28T14:47:53.203 回答
8

正如思南指出的那样,最好的答案是使用Unicode::GCString


我稍微修改了Chas的例子:

  • 在 STDOUT 上设置编码以避免“打印中的宽字符”警告;
  • split在(显然,在 5.10 之后不起作用,所以我删除了它)中使用积极的前瞻断言(并且没有分隔符保留模式)

基本上是一样的,只是做了一些调整。

use strict;
use warnings;

binmode STDOUT, ":utf8";

my $original = "re\x{0301}sume\x{0301}";
my $wrong    = reverse $original;
my $right    = join '', reverse split /(\X)/, $original;

print <<HERE;
original: [$original]
   wrong: [$wrong]
   right: [$right]
HERE
于 2009-08-28T19:10:03.843 回答
2

您可以使用Unicode::GCString

Unicode::GCString 将 Unicode 字符串视为由 Unicode 标准附件 #29 [UAX #29] 定义的扩展字素簇序列。

#!/usr/bin/env perl

use utf8;
use strict;
use warnings;
use feature 'say';
use open qw(:std :utf8);

use Unicode::GCString;

my $x = "re\x{0301}sume\x{0301}";
my $y = Unicode::GCString->new($x);
my $wrong = reverse $x;
my $correct = join '', reverse @{ $y->as_arrayref };

say "$x -> $wrong";
say "$y -> $correct";

输出:

简历 -> ́emuśer
简历 -> émusér
于 2015-03-19T00:53:04.910 回答
1

Perl6::Str->reverse也可以。

在字符串的情况下résumé,您还可以在ing之前使用Unicode::Normalize核心模块将字符串更改为完全组合的形式(NFCNFKC) ;reverse但是,这不是一个通用的解决方案,因为基本字符和修饰符的某些组合没有预先组合的 Unicode 代码点。

于 2019-10-09T07:53:13.737 回答
0

其他一些答案包含效果不佳的元素。这是在 Perl 5.12 和 5.14 上测试的工作示例。未能指定 binmode 将导致输出生成错误消息。在 split 中使用积极的前瞻断言(并且没有分隔符保留模式)将导致我的 Macbook 上的输出不正确。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'unicode_strings';

binmode STDOUT, ":utf8";

my $original = "re\x{0301}sume\x{0301}";
my $wrong    = reverse $original;
my $right    = join '', reverse split /(\X)/, $original;
print "original: $original\n",
      "wrong:    $wrong\n",
      "right:    $right\n";
于 2012-01-25T05:24:26.037 回答