web-dev-qa-db-fra.com

Convertissez tous les types de devis intelligents avec PHP

J'essaie de convertir tous les types de citations intelligentes en citations régulières lorsque je travaille avec du texte. Cependant, la fonction suivante que j'ai compilée semble toujours manquer de support et de conception appropriée.

Est-ce que quelqu'un sait comment convertir correctement tous les guillemets ?

function convert_smart_quotes($string)
{
    $quotes = array(
        "\xC2\xAB"   => '"', // « (U+00AB) in UTF-8
        "\xC2\xBB"   => '"', // » (U+00BB) in UTF-8
        "\xE2\x80\x98" => "'", // ‘ (U+2018) in UTF-8
        "\xE2\x80\x99" => "'", // ’ (U+2019) in UTF-8
        "\xE2\x80\x9A" => "'", // ‚ (U+201A) in UTF-8
        "\xE2\x80\x9B" => "'", // ‛ (U+201B) in UTF-8
        "\xE2\x80\x9C" => '"', // “ (U+201C) in UTF-8
        "\xE2\x80\x9D" => '"', // ” (U+201D) in UTF-8
        "\xE2\x80\x9E" => '"', // „ (U+201E) in UTF-8
        "\xE2\x80\x9F" => '"', // ‟ (U+201F) in UTF-8
        "\xE2\x80\xB9" => "'", // ‹ (U+2039) in UTF-8
        "\xE2\x80\xBA" => "'", // › (U+203A) in UTF-8
    );
    $string = strtr($string, $quotes);

    // Version 2
    $search = array(
        chr(145),
        chr(146),
        chr(147),
        chr(148),
        chr(151)
    );
    $replace = array("'","'",'"','"',' - ');
    $string = str_replace($search, $replace, $string);

    // Version 3
    $string = str_replace(
        array('‘','’','“','”'),
        array("'", "'", '"', '"'),
        $string
    );

    // Version 4
    $search = array(
        '‘', 
        '’', 
        '“', 
        '”', 
        '—',
        '–',
    );
    $replace = array("'","'",'"','"',' - ', '-');
    $string = str_replace($search, $replace, $string);

    return $string;
}

Remarque: Cette question est une requête complète sur la gamme complète de citations, y compris les "Microsoft" citations posées ici Ceci est un "doublon" de la même manière que poser des questions sur toutes les tailles de pneus est un "doublon" "de demander une taille de pneu de voiture.

23
Xeoncross

Vous avez besoin de quelque chose comme ça (en supposant une entrée UTF-8 et en ignorant CJK (chinois, japonais, coréen)):

$chr_map = array(
   // Windows codepage 1252
   "\xC2\x82" => "'", // U+0082⇒U+201A single low-9 quotation mark
   "\xC2\x84" => '"', // U+0084⇒U+201E double low-9 quotation mark
   "\xC2\x8B" => "'", // U+008B⇒U+2039 single left-pointing angle quotation mark
   "\xC2\x91" => "'", // U+0091⇒U+2018 left single quotation mark
   "\xC2\x92" => "'", // U+0092⇒U+2019 right single quotation mark
   "\xC2\x93" => '"', // U+0093⇒U+201C left double quotation mark
   "\xC2\x94" => '"', // U+0094⇒U+201D right double quotation mark
   "\xC2\x9B" => "'", // U+009B⇒U+203A single right-pointing angle quotation mark

   // Regular Unicode     // U+0022 quotation mark (")
                          // U+0027 apostrophe     (')
   "\xC2\xAB"     => '"', // U+00AB left-pointing double angle quotation mark
   "\xC2\xBB"     => '"', // U+00BB right-pointing double angle quotation mark
   "\xE2\x80\x98" => "'", // U+2018 left single quotation mark
   "\xE2\x80\x99" => "'", // U+2019 right single quotation mark
   "\xE2\x80\x9A" => "'", // U+201A single low-9 quotation mark
   "\xE2\x80\x9B" => "'", // U+201B single high-reversed-9 quotation mark
   "\xE2\x80\x9C" => '"', // U+201C left double quotation mark
   "\xE2\x80\x9D" => '"', // U+201D right double quotation mark
   "\xE2\x80\x9E" => '"', // U+201E double low-9 quotation mark
   "\xE2\x80\x9F" => '"', // U+201F double high-reversed-9 quotation mark
   "\xE2\x80\xB9" => "'", // U+2039 single left-pointing angle quotation mark
   "\xE2\x80\xBA" => "'", // U+203A single right-pointing angle quotation mark
);
$chr = array_keys  ($chr_map); // but: for efficiency you should
$rpl = array_values($chr_map); // pre-calculate these two arrays
$str = str_replace($chr, $rpl, html_entity_decode($str, ENT_QUOTES, "UTF-8"));

Voici le contexte:

Chaque caractère Unicode appartient à exactement un "Catégorie générale" , dont ceux qui peuvent contenir des guillemets sont les suivants:

(ces pages sont pratiques pour vérifier que vous n'avez rien manqué - il y a aussi un index des catégories )

Il est parfois utile de correspondre à ces catégories dans une expression régulière compatible Unicode.

De plus, les caractères Unicode ont "propriétés" , dont celui qui vous intéresse est Quotation_Mark . Malheureusement, ceux-ci ne sont pas accessibles dans une expression régulière.

Dans Wikipedia, vous pouvez trouver le groupe de caractères avec la propriété Quotation_Mark . La référence finale est PropList.txt sur unicode.org, mais il s'agit d'un fichier texte ASCII.

Dans le cas où vous devez également traduire des caractères CJK, il vous suffit d'obtenir leurs points de code, de décider de leur traduction et de trouver leur codage UTF-8, par exemple, en le recherchant dans fileformat.info (par exemple, pour U + 301E: - http://www.fileformat.info/info/unicode/char/301e/index.htm ).

En ce qui concerne la page de codes 1252 de Windows: nicode définit les 256 premiers points de code pour représenter exactement les mêmes caractères que ISO-8859-1 , mais ISO-8859-1 est souvent confondu avec - page de codes Windows 1252 , de sorte que tous les navigateurs affichent la plage 0x80-0x9F, qui est "vide" dans ISO-8859-1 (plus exactement: elle contient des caractères de contrôle), comme s'il s'agissait de la page de codes Windows 1252. Le tableau de la page Wikipedia répertorie les équivalents Unicode.

Remarque: strtr() est souvent plus lent que str_replace() . Le chronométrer avec votre entrée et votre PHP. Si c'est assez rapide, vous pouvez directement utiliser une carte comme mon $chr_map.


Si vous n'êtes pas sûr que votre entrée est encodée en UTF-8, ET êtes prêt à supposer que si ce n'est pas le cas, alors c'est ISO-8859-1 ou la page de codes 1252 de Windows, alors vous pouvez le faire avant toute autre chose:

if ( !preg_match('/^\\X*$/u', $str)) {
   $str = utf8_encode($str);
}

Attention: cette expression régulière peut dans de très rares cas ne pas détecter un encodage non UTF-8. Par exemple: "Gruß…"/*CP-1252*/=="Gru\xDF\x85" Ressemble à UTF-8 pour cette expression régulière (U + 07C5 est le chiffre N'ko 5). Ce regex peut être légèrement amélioré, mais malheureusement, il peut être démontré qu'il n'existe AUCUNE solution complètement infaillible au problème de la détection de codage.


Si vous souhaitez normaliser la plage 0x80-0x9F qui provient de la page de codes 1252 de Windows aux points de code Unicode normaux, vous pouvez le faire (et supprimer la première partie du $chr_map Ci-dessus):

$normalization_map = array(
   "\xC2\x80" => "\xE2\x82\xAC", // U+20AC Euro sign
   "\xC2\x82" => "\xE2\x80\x9A", // U+201A single low-9 quotation mark
   "\xC2\x83" => "\xC6\x92",     // U+0192 latin small letter f with hook
   "\xC2\x84" => "\xE2\x80\x9E", // U+201E double low-9 quotation mark
   "\xC2\x85" => "\xE2\x80\xA6", // U+2026 horizontal Ellipsis
   "\xC2\x86" => "\xE2\x80\xA0", // U+2020 dagger
   "\xC2\x87" => "\xE2\x80\xA1", // U+2021 double dagger
   "\xC2\x88" => "\xCB\x86",     // U+02C6 modifier letter circumflex accent
   "\xC2\x89" => "\xE2\x80\xB0", // U+2030 per mille sign
   "\xC2\x8A" => "\xC5\xA0",     // U+0160 latin capital letter s with caron
   "\xC2\x8B" => "\xE2\x80\xB9", // U+2039 single left-pointing angle quotation mark
   "\xC2\x8C" => "\xC5\x92",     // U+0152 latin capital ligature oe
   "\xC2\x8E" => "\xC5\xBD",     // U+017D latin capital letter z with caron
   "\xC2\x91" => "\xE2\x80\x98", // U+2018 left single quotation mark
   "\xC2\x92" => "\xE2\x80\x99", // U+2019 right single quotation mark
   "\xC2\x93" => "\xE2\x80\x9C", // U+201C left double quotation mark
   "\xC2\x94" => "\xE2\x80\x9D", // U+201D right double quotation mark
   "\xC2\x95" => "\xE2\x80\xA2", // U+2022 bullet
   "\xC2\x96" => "\xE2\x80\x93", // U+2013 en dash
   "\xC2\x97" => "\xE2\x80\x94", // U+2014 em dash
   "\xC2\x98" => "\xCB\x9C",     // U+02DC small tilde
   "\xC2\x99" => "\xE2\x84\xA2", // U+2122 trade mark sign
   "\xC2\x9A" => "\xC5\xA1",     // U+0161 latin small letter s with caron
   "\xC2\x9B" => "\xE2\x80\xBA", // U+203A single right-pointing angle quotation mark
   "\xC2\x9C" => "\xC5\x93",     // U+0153 latin small ligature oe
   "\xC2\x9E" => "\xC5\xBE",     // U+017E latin small letter z with caron
   "\xC2\x9F" => "\xC5\xB8",     // U+0178 latin capital letter y with diaeresis
);
$chr = array_keys  ($normalization_map); // but: for efficiency you should
$rpl = array_values($normalization_map); // pre-calculate these two arrays
$str = str_replace($chr, $rpl, $str);
74
Walter Tross

Vous pouvez utiliser cette fonction pour convertir tous les caractères:

$output = iconv('UTF-8', 'ASCII//TRANSLIT', $input);

Soyez sûr et changez vos types selon vos besoins.

(note: ceci provient d'une autre question similaire trouvée ici ).

9
Lokiare