2016-02-13 32 views
6

Czy jest jakiś sposób w wyrażeniu regularnym, aby określić dopasowanie dla postaci z określonym znakiem diakrytycznym? Powiedzmy na przykład poważny akcent. Długa droga do tego jest, aby przejść do Wikipedia page on the grave accent, skopiuj wszystkie znaki, to pokazuje, a następnie dokonać klasę postaci z nich:Dopasuj znak regex z określonym znakiem diakrytycznym

/[àầằèềḕìǹòồṑùǜừẁỳ]/i 

to dość uciążliwe. Miałem nadzieję na własności Unicode, takie jak \p{hasGraveAccent}, ale nie mogę znaleźć czegoś takiego. Szukając rozwiązania, pojawiają się tylko pytania osób, które próbują dopasować znaki, ignorując znaki diakrytyczne, co wymaga pewnego rodzaju normalizacji, czego nie chcę.

+0

Jeśli jest to znak łączący, może to być możliwe przez [generowanie listy punktów kodowych unikodowych] (http://stackoverflow.com/questions/17051732/algorithm-to-check-for-combing-character-in-unicode). – kba

+0

Stwórz klasę znaków z pojedynczych liter nie jest niezawodny i nie działałby.Działałoby to tylko dla wstępnie skomponowanych liter pasujących do NFC (złożona forma normalizacyjna). Większość postaci z dwoma lub więcej znakami diakrytycznymi nie ma wstępnego charakteru. To znaczy. składają się z więcej niż jednego punktu kodowego (= znak w mowie Unicode). Jeśli skopiujesz i wkleisz je do klasy znaków, znak diakrytyczny nadal będzie pojedynczym znakiem i będzie pasował do tych samych znaków diakrytycznych w ciągu docelowym. –

Odpowiedz

0

To trochę trudne pytanie, ale jest to możliwe. Najpierw musisz znormalizować ciąg unicode w jednym z 4 formularzy. Informacje na temat normalizacji to here, a mapa przykładów znaków z różnymi normalizacjami to here, a dobrym wykresem dla znormalizowanych znaków jest here. Zasadniczo, normalizacja po prostu zapewnia, że ​​wszystkie znaki są w tym samym formacie podczas posługiwania się znakami diakrytycznymi. Golang ma wielkie poparcie dla tego, a większość języków powinna zawierać biblioteki do tego.

Tak więc dla mojego przykładu skonwertuj ciąg znaków do "Normalization Form D" (NFD) i utf32, więc wszystkie znaki Unicode są ich punktami kodowymi w 4 bajtach.

Wszystkie znaki diakrytyczne dla akcentu poważnego mają 0x0300 obok znaku. Możesz więc użyć wyszukiwania wyrażenia regularnego w trybie ASCII (NIE w trybie Unicode) dla ....\x00\x00\x03\x00. Stamtąd musisz wyodrębnić, w której lokalizacji runy. Można to zrobić różnymi metodami w zależności od używanego kodowania.

Więc jeśli wylądujesz w dziale 4, będziesz znać jego prawidłową postać.

Oprócz tego nie istnieją oficjalne grupy znaków perla, które mogłyby to zrobić.

kod Perl jako przykład:

use Encode; 
use Unicode::Normalize; 

$StartUTF8='xàaâèaê'; 
$PerlEncoded=decode('utf8', $StartUTF8); 
$PerlNormalized=NFD($PerlEncoded); 
$UTF32Normalized=encode('utf32', $PerlNormalized); 

while($UTF32Normalized =~ /(....\x00\x00\x03\x00)/gs) { 
    $Pos=pos($UTF32Normalized)-8; 
    if($Pos%4==0) { 
     print("$Pos\n"); 
    } 
} 

Ale w tym momencie, to równie dobrze może być po prostu robi dla pętli ciągu znaków: - \

Próbowałem też dopasowanie bez potrzeby pozycję przetestuj używając // c, ale z jakiegoś powodu to nie zadziała.

/^(?:....)*?(....\x00\x00\x03\x00)/gcs

+0

Nie ma sensu konwersja do UTF32 (a jeśli zakładasz, że wynik to UTF-32LE, powinieneś przekonwertować to na niego, zamiast pozostawić go przypadkowi). Również założenie, że akcent godny brzmi bezpośrednio po znaku bazowym, może być nieprawidłowe, gdy glif zawiera więcej niż jeden znak diakrytyczny. – rici

+0

Rzeczywiście. To było dość bezowocne badania i testy – Dakusan

1

Jest to możliwe z pewnymi ograniczeniami.

#!perl 

use strict; 
use warnings; 

use Encode; 
use Unicode::Normalize; 
use charnames qw(); 
use utf8; # source is utf-8 

binmode(STDOUT, ":utf8"); # print in utf-8 

my $utf8_string = 'xàaâèaêòͤ'; 

my $nfd_string = NFD($utf8_string); # decompose 

my @chars_with_grave = $nfd_string =~ 
    m/ 
    (
     \p{L}   # one letter 
     \p{M}*   # 0 or more marks 
     \N{COMBINING GRAVE ACCENT} 
     \p{M}*   # 0 or more marks 
    ) 
    /xmsg; 

print join(', ',@chars_with_grave), "\n"; 

Drukuje

$ perl utf_match_grave.pl 
à, è, òͤ 

UWAGA: znaki w obszarze edycji są prawidłowo wyświetlane jako połączone, ale stackoverflow czyni je niewłaściwie oddzielone.

Wymaga litery jako postaci podstawowej. Zmień wyrażenie regularne dla innych znaków podstawowych. Mark \p{M} może nie jest dokładnie tym, czego potrzebujesz, powinien zostać ulepszony.