Question

J'ai commencé avec quelques échecs fous en utilisant preg_replace en php et on fait bouillir vers le bas au cas de problème d'avoir plus d'une classe de caractères en utilisant pointillé turc « i » et undotted « ı » ensemble. Voici un exemple simple de test en php:

<?php
    echo 'match single normal i: ';
    $str = 'mi';
    echo (preg_match('!m[ıi]!', $str)) ? "ok\n" : "fail\n";

    echo 'match single undotted ı: ';
    $str = 'mı';
    echo (preg_match('!m[ıi]!', $str)) ? "ok\n" : "fail\n";

    echo 'match double normal i: ';
    $str = 'misir';
    echo (preg_match('!m[ıi]s[ıi]r!', $str)) ? "ok\n" : "fail\n";

    echo 'match double undotted ı: ';
    $str = 'mısır';
    echo (preg_match('!m[ıi]s[ıi]r!', $str)) ? "ok\n" : "fail\n";
?>

Et encore une fois le même cas de test en perl:

#!/usr/bin/perl

$str = 'mi';
$str =~ m/m[ıi]/ && print "match single normal i\n";

$str = 'mı';
$str =~ m/m[ıi]/ && print "match single undotted ı\n";

$str = 'misir';
$str =~ m/m[ıi]s[ıi]r/ && print "match double normal i\n";

$str = 'mısır';
$str =~ m/m[ıi]s[ıi]r/ && print "match double undotted ı\n";

Les trois premiers tests excellent travail. Le dernier ne correspond pas.

Pourquoi ce beau travail en tant que classe de caractère une fois, mais pas la deuxième fois dans la même expression? Comment puis-je écrire une expression pour correspondre à un mot comme celui-ci qui doit correspondre à peu importe quelles combinaisons de lettres, il est écrit avec?

Modifier Informations générales sur le problème linguistique Je suis en train de programme.

Edit 2: Ajout d'une directive ne fixe use utf8; la version perl. Depuis mon problème d'origine était avec un programme php et je ne passe à Perl pour voir si elle était un bug en php, cela ne me aide pas beaucoup. Quelqu'un sait-il que la directive PHP faire pas étouffer à ce sujet?

Était-ce utile?

La solution

séquences multi-octets ne fera pas ce que vous voulez dans les classes char entre parenthèses si le UTF-8 est d'être mal-interprété comme une séquence d'octets de 8 bits. Penses-y. Si [nñm] est misconstructed pas trois caractères logiques mais quatre octets physiques, vous ne correspondre à un personnage dont le point de code est 6E ou C3 ou B1 ou 6D.

Dans certains cas, vous pourriez vous en sortir avec la réécriture [nñm] comme (?:n|ñ|m). Cela dépend de ce que vous faites. choses boîtier ne fonctionnera pas.

En outre, Unicode a des règles de forme spéciale pour un dotless turc i.

Sons comme PHP est tout simplement pas assez moderne. Soupir.

Autres conseils

Vous devrez peut-être demander à Perl que votre fichier source contient des caractères UTF8. Essayez:

#!/usr/bin/perl

use utf8;   # **** Add this line

$str = 'mısır';
$str =~ m/m[ıi]s[ıi]r/ && print "match double undotted ı\n";

Ce qui ne vous aide pas avec PHP, mais il peut y avoir une directive similaire en PHP. Dans le cas contraire, essayez d'utiliser une forme d'évasion séquence pour éviter de mettre le caractère littéral dans votre code source. Je ne sais rien à propos de PHP donc je ne peux pas aider.

Modifier Je lis que PHP n'a pas de support Unicode. Par conséquent, l'entrée unicode vous passez est probablement traité comme la chaîne d'octets que le unicode a été encodées comme.

Si vous pouvez être assuré que votre entrée arrive en tant que utf-8 alors vous pouvez correspondre à la séquence utf-8 pour ı qui est \xc4 \xb1 comme dans:

$str = 'mısır';  # Make sure this source-file is encoded as utf-8 or this match will fail
echo (preg_match('!m(i|\xc4\xb1)s(i|\xc4\xb1)r!', $str)) ? "ok\n" : "fail\n";

Est-ce que le travail?

Modifier à nouveau: Je peux expliquer pourquoi vos trois premiers tests passent. Feignons que l'encodage, ı est codé comme ABCDE. puis PHP voit ce qui suit:

echo 'match single normal i: ';
$str = 'mi';
echo (preg_match('!m[ABCDEi]!', $str)) ? "ok\n" : "fail\n";

echo 'match single undotted ABCDE: ';
$str = 'mABCDE';
echo (preg_match('!m[ABCDEi]!', $str)) ? "ok\n" : "fail\n";

echo 'match double normal i: ';
$str = 'misir';
echo (preg_match('!m[ABCDEi]s[ABCDEi]r!', $str)) ? "ok\n" : "fail\n";

echo 'match double undotted ABCDE: ';
$str = 'mABCDEsABCDEr';
echo (preg_match('!m[ABCDEi]s[ABCDEi]r!', $str)) ? "ok\n" : "fail\n";

ce qui le rend évident pourquoi les trois premiers tests passent et le dernier échoue. Si vous utilisez un début / fin ^...$ d'ancrage Je pense que vous trouverez que seul le premier test passe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top