2016-02-13 8 views
6

Gibt es eine Möglichkeit in einer Regex eine Übereinstimmung für ein Zeichen mit einem bestimmten diakritischen angeben? Sagen wir zum Beispiel einen ernsten Akzent. Der lange Weg, dies zu tun ist, um die Wikipedia page on the grave accent zu gehen, kopieren Sie alle Zeichen zeigt es, dann eine Zeichenklasse machen aus ihnen heraus:Regex Match-Zeichen mit spezifischen diakritischen

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

Das ziemlich langweilig ist. Ich hatte auf eine Unicode-Eigenschaft wie \p{hasGraveAccent} gehofft, aber ich kann nichts dergleichen finden. Die Suche nach einer Lösung führt nur zu Fragen von Leuten, die versuchen, Charaktere zu finden, während sie Diakritika ignorieren, was eine Art von Normalisierung beinhaltet, was ich nicht will.

+0

Wenn es ein Kombinationszeichen ist, das könnte möglich sein, durch [eine Liste von Unicode-Codepunkten zu erzeugen] (http://stackoverflow.com/questions/17051732/algorithm-to-check-for-combining-characters-in-unicode). – kba

+0

Machen Sie eine Zeichenklasse aus einzelnen Buchstaben ist nicht zuverlässig und würde nicht funktionieren.Es würde nur für vorkomparierte Buchstaben funktionieren, die Strings NFC (Normalisierungsform zusammengesetzt) ​​entsprechen. Die meisten Zeichen mit zwei oder mehr Diakritika haben keinen vorkomparierten Charakter. I.e. Sie bestehen aus mehr als einem Codepunkt (= Zeichen in Unicode-Sprache). Wenn Sie sie kopieren und in eine Zeichenklasse einfügen, ist das Diakritikum immer noch ein einzelnes Zeichen und wird mit den gleichen einzelnen Diakritika in der Zielzeichenfolge übereinstimmen. –

Antwort

0

Es ist eine knifflige Frage, aber es ist möglich. Zuerst müssen Sie die Unicode-Zeichenfolge in eine der 4 Formen normalisieren. Informationen zur Normalisierung sind here, und eine Zuordnung von Zeichenbeispielen mit den verschiedenen Normalisierungen ist here, und ein gutes Diagramm für die normalisierten Zeichen ist here. Im Wesentlichen stellt das Normalisieren nur sicher, dass alle Zeichen im selben Format sind, wenn sie mit Diakritika umgehen. Golang hat dafür eine große Unterstützung, und die meisten Sprachen sollten Bibliotheken dafür enthalten.

Also für mein Beispiel, konvertieren Sie Ihre Zeichenfolge in "Normalisierung Form D" (NFD) und utf32, so dass alle Unicode-Zeichen sind ihre Codepunkte in 4 Bytes.

Alle diakritischen Zeichen für den Grabakzent haben 0x0300 neben dem Zeichen. Sie können also einen regulären Ausdruck im ASCII-Modus (NICHT im Unicode-Modus) für ....\x00\x00\x03\x00 suchen. Von dort müsstest du herausfinden, in welchem ​​Runen-Ort es sich befindet. Das kann mit verschiedenen Methoden geschehen, abhängig davon, welche Kodierung du verwendest.

Wenn Sie also auf eine Division von 4 landen, wissen Sie, dass es sich um einen gültigen Charakter handelt.

Darüber hinaus gibt es keine offiziellen Perl-Zeichengruppierungen, um dies zu tun.

Perl-Code als Beispiel:

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"); 
    } 
} 

Aber an diesem Punkt, dann kann man auch nur eine for-Schleife über die Zeichen tun: - \

Ich versuchte auch ohne Anpassung der Position zu benötigen Test mit // c, aber aus irgendeinem Grund würde es nicht funktionieren.

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

+0

Es gibt keinen Punkt, der in UTF32 konvertiert wird (und wenn Sie davon ausgehen, dass UTF-32LE das Ergebnis ist, sollten Sie dies konvertieren, anstatt es dem Zufall zu überlassen). Auch die Annahme, dass der Grabakzent unmittelbar dem Basiszeichen folgt, kann falsch sein, wenn die Glyphe mehr als ein Diakritikum enthält. – rici

+0

In der Tat. Es war ziemlich fruchtlos Forschung und Tests – Dakusan

1

Es ist mit einigen Einschränkungen möglich.

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

Dieser druckt

$ perl utf_match_grave.pl 
à, è, òͤ 

HINWEIS: Die Zeichen im Bearbeitungsbereich richtig in Kombination angezeigt, sondern macht sie falsch Stackoverflow getrennt.

Es benötigt einen Buchstaben als Basiszeichen. Ändern Sie die Regex für andere Basiszeichen. Mark \p{M} ist vielleicht nicht genau das, was Sie wollen, sollte verbessert werden.