2016-02-13 2 views
6

Existe-t-il un moyen de spécifier une correspondance pour un caractère avec un signe diacritique spécifique dans une expression régulière? Disons un accent grave par exemple. Le long chemin à faire est d'aller à la Wikipedia page on the grave accent, copier tous les caractères montre, puis faire une classe de personnage hors d'eux:Caractère de correspondance regex avec un signe diacritique spécifique

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

C'est assez fastidieux. J'espérais une propriété Unicode comme \p{hasGraveAccent}, mais je ne trouve rien de tel. La recherche d'une solution ne pose que des questions de personnes essayant de faire correspondre les caractères tout en ignorant les signes diacritiques, ce qui implique d'effectuer une normalisation quelconque, ce qui n'est pas ce que je veux.

+0

S'il s'agit d'un caractère de combinaison, cela peut être possible en [générant une liste de points de code Unicode] (http://stackoverflow.com/questions/17051732/algorithm-to-check-for-combining-characters-in-unicode). – kba

+0

Faire une classe de caractères en lettres simples n'est pas fiable et ne fonctionnerait pas.Cela ne fonctionnerait que pour les lettres précomposées correspondant aux chaînes NFC (formulaire de normalisation composé). La plupart des personnages avec deux ou plusieurs signes diacritiques n'ont aucun caractère précomposé. C'est à dire. ils sont constitués de plus d'un point de code (= caractère dans le discours Unicode). Si vous les copiez et les collez dans une classe de caractères, le signe diacritique est toujours un caractère unique et correspondra aux mêmes signes diacritiques dans la chaîne cible. –

Répondre

0

C'est une question un peu délicate, mais c'est possible. Tout d'abord, vous devez normaliser la chaîne unicode dans l'une des 4 formes. Informations sur la normalisation est here et une carte d'exemples de caractères avec les différentes normalisations est here et un bon graphique pour les caractères normalisés est here. Essentiellement, la normalisation s'assure que tous les caractères sont dans le même format lors de la manipulation des signes diacritiques. Golang a un grand soutien pour cela, et la plupart des langues devraient contenir des bibliothèques pour cela. Donc, pour mon exemple, convertissez votre chaîne en "Normalisation Form D" (NFD) et utf32, donc tous les caractères Unicode sont leurs points de code dans 4 octets.

Tous les caractères diacritiques pour l'accent grave ont 0x0300 à côté du caractère. Vous pouvez donc effectuer une recherche d'expression régulière en mode ascii (mode NOT unicode) pour ....\x00\x00\x03\x00. De là, vous devrez extraire l'emplacement de la rune. Cela peut être fait avec différentes méthodes en fonction de l'encodage que vous utilisez. Donc, si vous atterrissez sur une division de 4, vous saurez que c'est un caractère valide. En outre, il n'y a pas de groupements de caractères perl officiels pour le faire.

code Perl comme exemple:

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

Mais à ce stade, vous pourriez aussi bien juste faire une boucle sur les caractères: - \

J'ai aussi essayé correspondant sans avoir besoin de la position test en utilisant // c, mais pour une raison quelconque, cela ne fonctionnerait pas.

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

+0

Il n'y a aucun point à convertir en UTF32 (et, si vous allez supposer que le résultat est UTF-32LE, vous devriez convertir en UTF-32 plutôt que de le laisser au hasard). De même, l'hypothèse selon laquelle l'accent grave suit immédiatement le caractère de base peut être incorrecte lorsque le glyphe contient plus d'un signe diacritique. – rici

+0

En effet. C'était une recherche et des essais plutôt stériles – Dakusan

1

Il est possible avec certaines limites.

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

Cette imprime

$ perl utf_match_grave.pl 
à, è, òͤ 

NOTE: Les caractères dans la zone d'édition sont correctement affichées sous forme combinée, mais stackoverflow les rend mal séparés.

Il a besoin d'une lettre comme caractère de base. Changez la regex pour les autres caractères de base. Mark \p{M} n'est peut-être pas exactement ce que vous voulez, devrait être amélioré.