2009-08-28 22 views
11

"re\x{0301}sume\x{0301}" dizesini aldım (bu şöyle yazdırılır: re & # x0301; sume & # x0301;) ve onu "e\x{0301}muse\x{0301}r" (e & # x0301; muse & # x0301; r) olarak değiştirmek istiyorum. reverse Perl'sini kullanamıyorum çünkü "\x{0301}" gibi karakterleri ayrı karakterler olarak birleştiriyor, bu yüzden "\x{0301}emus\x{0301}er" (& # x0301; emus & # x0301; er) almaktan vazgeçiyorum. Dizgiyi nasıl tersine çevirebilirim, ancak yine de birleştiren karakterlere saygı duyarım?Perl'de karakterleri birleştiren bir dizeyi nasıl geri alabilirim?

cevap

8

iyi cevap ben Chas örneğinin değiştirilmiş biraz as Sinan points out


, Unicode::GCString kullanmaktır:

  • "Baskıda geniş karakter" uyarılarından kaçınmak için STDOUT'daki kodlamayı ayarlayın; Temelde tweaks bir çift ile aynı şey

  • (görünüşte, 5.10 sonra çalışmaz, bu yüzden kaldırıldı) split bir pozitif ileri yönlü onaylama işlemi (ve hiçbir ayırıcı tutma modu) kullanın.

    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 
    
  • +0

    Vay. Perl'i severim, ama bu bölünmüş ifade oldukça büyülüdür. İlk düşüncem “kaba kuvvet” idi: bölünmenin yaptıklarını yapmak için bir işlev yapmak - her bir girişi mantıksal bir karakteri temsil eden dizelerin bir listesini döndürmek. Ancak bu listeyi (@x olarak adlandır) alırsınız, neyse ki, ('', ters (@x)) birleşme kısmı açıktır. – Roboprog

    +2

    Büyülü? Nasıl yani? Hiçbir yan etkisi olmayan bir regex ve sadece tam olarak gördüğünüz şeyi yapar. Eğer bu sihrin olduğunu düşünüyorsanız, Perl'in gerçek siyah sanatlarını görmediniz. Sen zeki diyebilirsin (yine de söylemem) ama büyülü değil. Muhtemelen hiç kullanmadığın bir şey. –

    +0

    Bu örneği Perl v5.12.4 kullanarak çalıştırmayı denedim ve işe yaramadı. Bunun yerine/(\ X)/kullanın. Bu soru cevabı Perl'in önceki sürümlerinde çalıştı mı, yoksa sadece belli olanı mı özledik? – Flimm

    12

    Sen join sonra \X special escape grafemler listesini (aralarında boş dizeleri ile) grafemler bir listesini yapmak için split ile (non-birleştirerek karakter ve aşağıdaki birleştirerek tüm karakterlerle eşleştiğinde) ters onları geri kullanabilirsiniz birlikte:

    #!/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

    (Ben ilk başta olduğu gibi) hakkında grafemler arasındaki boş dizeler vardır neden 'split' ters çevrilmesi nedeniyle, bu: bu verileri kullanır Bu ayırıcı olarak aranıyor. Boş dize, "aradaki" iki grafiktir. Sadece ayırıcıyı dahil ederek, "gerçek" sonuçla karışık grafikleri aldığınız sonucu elde edebilirsiniz - bir dizi boş dizge. Bunun yerine grafikler yakalamak için bir 'm // g' kullanmaktan kaçınan alternatif (ve biraz daha hızlı) bir yöntem:' join '', tersine $ orijinal = ~/(\ X)/g' –

    +2

    Michael’ın yorumunu açıklığa kavuşturmak için bellek parantezini ayırdığınız bir normal ifadede kullandığınızda, "ayırıcı tutma modu" tetiklenir. Ayrıldığın parçalar arasında geçen şeyi geri alırsın. Ancak bunu yapmak zorunda değilsiniz. Desen (? = \ X), ekstra bir bit olmadan aynı şeyi yapar. Boş dize, küçük dizeler için bu kadar önemli değil. –

    +0

    "Ayırıcı tutma modu" nu işaret etmekte haklısınız, teşekkür ederim, bu yardımcı oldu. Ancak, (? = \ X) eşdeğer değildir. ispatı için, bu iki örneği ele alalım: bölme/(a) /, "abc" (? = A) /, "abc" ve bölünmüş/(b + c) 'bölme/eşdeğer değildir/"abbcd",/(? = b + c) /, "abbcd" – Flimm

    0

    Diğer yanıtların bazıları iyi çalışmayan öğeler içerir. İşte Perl 5.12 ve 5.14 üzerinde test edilmiş bir çalışma örneğidir. Binmode belirtilememesi, çıktının hata mesajları üretmesine neden olur. Bölme içinde pozitif bir göz atma iddiası (ve ayırıcı tutma modu yok) kullanmak, Macbook'umda çıktının yanlış olmasına neden olur.

    #!/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"; 
    
    2

    Sen Unicode::GCString kullanabilirsiniz: Unicode Standard tarafından tanımlanan genişletilmiş sesletim kümelerinden oluşan bir dizi [UAX # 29] 29. Ek olarak

    Unicode :: GCString Unicode dize davranır.

    #!/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"; 
    

    Çıktı: karıştı olanlar için

    résumé -> ́emuśer 
    résumé -> émusér
    İlgili konular