如何反转包含Perl中的字符组合的字符串?

时间:2009-08-28 14:47:37

标签: perl unicode string reverse

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

5 个答案:

答案 0 :(得分:12)

您可以使用\X special escape(匹配非组合字符和以下所有组合字符)和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";

答案 1 :(得分:8)

最佳答案是使用Unicode::GCStringas Sinan points out


我稍微修改了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

答案 2 :(得分: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";

输出:

résumé -> ́emuśer
résumé -> émusér

答案 3 :(得分:1)

Perl6::Str ->reverse也可以。

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

答案 4 :(得分:0)

其他一些答案包含效果不佳的元素。这是一个在Perl 5.12和5.14上测试的工作示例。未能指定binmode将导致输出生成错误消息。在拆分中使用正向前瞻断言(并且没有分隔符保留模式)将导致我的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";