Как я могу перевернуть строку, которая содержит символы объединения в Perl? - PullRequest
12 голосов
/ 28 августа 2009

У меня есть строка "re\x{0301}sume\x{0301}" (которая печатается следующим образом: re & # x0301; sume & # x0301;), и я хочу изменить ее на "e\x{0301}muse\x{0301}r" (e & # x0301; muse & # x0301; r). Я не могу использовать Perl reverse, потому что он обрабатывает комбинированные символы, такие как "\x{0301}", как отдельные символы, поэтому я получаю "\x{0301}emus\x{0301}er" (& # x0301; emus & # x0301; er). Как я могу перевернуть строку, но при этом соблюдать символы объединения?

Ответы [ 4 ]

12 голосов
/ 28 августа 2009

Вы можете использовать \ X специальный 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";
8 голосов
/ 28 августа 2009

Лучший ответ - использовать Unicode :: GCString , , как указывает Синан

<Ч />

Я немного изменил пример Часа:

  • Установите кодировку на 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 голосов
/ 19 марта 2015

Вы можете использовать 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
0 голосов
/ 25 января 2012

Некоторые другие ответы содержат элементы, которые не работают хорошо. Вот рабочий пример, протестированный на 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";
...