PHP заменяет специальные символы, такие как à-›a, è-›e

У меня есть php-документ signup.php, который сохраняет содержимое из формы (в документе form.php) в базу MySQL. Проблема возникает, когда я хочу переформатировать входной контент. Я хочу декодировать символы UTF-8, например à->a.

  $first_name=$_POST['first_name'];
  $last_name=$_POST['last_name'];
  $course=$_POST['course'];

  $chain="prêt-à-porter";

$pattern = array("'é'", "'è'", "'ë'", "'ê'", "'É'", "'È'", "'Ë'", "'Ê'", "'á'", "'à'", "'ä'", "'â'", "'å'", "'Á'", "'À'", "'Ä'", "'Â'", "'Å'", "'ó'", "'ò'", "'ö'", "'ô'", "'Ó'", "'Ò'", "'Ö'", "'Ô'", "'í'", "'ì'", "'ï'", "'î'", "'Í'", "'Ì'", "'Ï'", "'Î'", "'ú'", "'ù'", "'ü'", "'û'", "'Ú'", "'Ù'", "'Ü'", "'Û'", "'ý'", "'ÿ'", "'Ý'", "'ø'", "'Ø'", "'œ'", "'Œ'", "'Æ'", "'ç'", "'Ç'");

$replace = array('e', 'e', 'e', 'e', 'E', 'E', 'E', 'E', 'a', 'a', 'a', 'a', 'a', 'A', 'A', 'A', 'A', 'A', 'o', 'o', 'o', 'o', 'O', 'O', 'O', 'O', 'i', 'i', 'i', 'I', 'I', 'I', 'I', 'I', 'u', 'u', 'u', 'u', 'U', 'U', 'U', 'U', 'y', 'y', 'Y', 'o', 'O', 'a', 'A', 'A', 'c', 'C'); 

$chain = preg_replace($pattern, $replace, $chain);

echo $chain; // print pret-a-porter

$first_name =  preg_replace($pattern, $replace, $first_name);

echo $first_name; // does not change the input!?!

Почему это отлично работает для $chain, но не работает для $first_name или $last_name?

Также я пытаюсь

echo $first_name; // print áááááábéééééébšššš
$trans = array("á" => "a", "é" => "e", "š" => "s");
echo strtr("áááááábéééééébšššš", $trans); // print aaaaaabeeeeeebssss
echo strtr($first_name,$trans);  // print áááááábéééééébšššš

но проблема, как видите, та же!


person Zoran Đukić    schedule 14.04.2012    source источник
comment
Ваш файл имеет правильную кодировку? Имеет ли материал в $_POST ту же кодировку? (то есть тот, который вы установили для браузера для отображения страницы?) Вы также можете установить флаг юникода для preg_replace   -  person phant0m    schedule 14.04.2012
comment
Как упоминает phant0m, вам нужно внимательно следить за всеми вашими кодировками. Кодировка по умолчанию с POST — ISO-8859-1, если вы не укажете конкретно, что хотите. (принять кодировку = 'UTF-8')   -  person dmp    schedule 14.04.2012
comment
добавил пару примеров функций :)   -  person dmp    schedule 14.04.2012
comment
Большое спасибо за вашу помощь, когда я добавляю accept-charset=UTF-8 в код ‹form action=sign_up.php method=post accept-charset=UTF-8›, работающий отлично.   -  person Zoran Đukić    schedule 14.04.2012


Ответы (7)


Есть гораздо более простой способ сделать это, используя iconv — судя по заметкам пользователя, это то, что вы хотите сделать: транслитерация символов

// PHP.net User notes
<?php
    $string = "ʿABBĀSĀBĀD";

    echo iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $string);
    // output: [nothing, and you get a notice]

    echo iconv('UTF-8', 'ISO-8859-1//IGNORE', $string);
    // output: ABBSBD

    echo iconv('UTF-8', 'ISO-8859-1//TRANSLIT//IGNORE', $string);
    // output: ABBASABAD
    // Yay! That's what I wanted!
?>

Будьте очень добросовестны с кодировками символов, чтобы вы сохраняли одну и ту же кодировку на всех этапах процесса — внешний интерфейс, отправка формы, кодировка исходных файлов. Кодировка по умолчанию в PHP и в формах — ISO-8859-1, до PHP 5.4, где она была изменена на UTF8 (наконец-то!).

Есть несколько функций, с которыми вы можете поиграть для идей. Первый из класса инфлектора CakePHP, который называется slug:

public static function slug($string, $replacement = '_') {
    $quotedReplacement = preg_quote($replacement, '/');

    $merge = array(
        '/[^\s\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]/mu' => ' ',
        '/\\s+/' => $replacement,
        sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '',
    );

    $map = self::$_transliteration + $merge;
    return preg_replace(array_keys($map), array_values($map), $string);
}

Это зависит от массива self::$_transliteration, который похож на то, что вы делали в своем вопросе - вы можете см. источник инфлектора на github.

Еще одна функция, которую я использую лично, берется отсюда.

function slugify($text,$strict = false) {
    $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
    // replace non letter or digits by -
    $text = preg_replace('~[^\\pL\d.]+~u', '-', $text);

    // trim
    $text = trim($text, '-');
    setlocale(LC_CTYPE, 'en_GB.utf8');
    // transliterate
    if (function_exists('iconv')) {
        $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
    }

    // lowercase
    $text = strtolower($text);
    // remove unwanted characters
    $text = preg_replace('~[^-\w.]+~', '', $text);
    if (empty($text)) {
        return 'empty_$';
    }
    if ($strict) {
        $text = str_replace(".", "_", $text);
    }
    return $text;
}

Эти функции транслитерируют и создают 'slugs' из произвольного ввода текста, который это очень полезная вещь, которую нужно иметь в своем наборе инструментов при создании веб-приложений. Надеюсь это поможет!

person dmp    schedule 14.04.2012
comment
Спасибо за ответ, проблема была в том, что я не добавил в форму accept-charset=UTF-8. - person Zoran Đukić; 14.04.2012
comment
Добро пожаловать, я думаю, что все эти функции на самом деле не нужны :), но вы также можете взглянуть. - person dmp; 14.04.2012
comment
Я продолжал использовать свою функцию, потому что с ее помощью я могу точно определить, какой буквой я заменю какую-то букву. - person Zoran Đukić; 14.04.2012
comment
Есть ли в любом случае сохранение рат? - person embe; 27.10.2016
comment
@embe может использовать iso-8859-1 вместо ascii? - person Svish; 13.01.2017
comment
Поскольку первый шаблон в $merge не содержит якорей (^, $), модификатор шаблона m не имеет смысла. - person mickmackusa; 21.09.2019

Вот способ иметь некоторую гибкость в том, что следует выбросить, а что заменить. Вот как я это делаю в настоящее время.

$string = 'À какая-то строка с мусором Ĩ Ä ';

$replace = [
    '&lt;' => '', '&gt;' => '', '&#039;' => '', '&amp;' => '',
    '&quot;' => '', 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'Ae',
    '&Auml;' => 'A', 'Å' => 'A', 'Ā' => 'A', 'Ą' => 'A', 'Ă' => 'A', 'Æ' => 'Ae',
    'Ç' => 'C', 'Ć' => 'C', 'Č' => 'C', 'Ĉ' => 'C', 'Ċ' => 'C', 'Ď' => 'D', 'Đ' => 'D',
    'Ð' => 'D', 'È' => 'E', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'Ē' => 'E',
    'Ę' => 'E', 'Ě' => 'E', 'Ĕ' => 'E', 'Ė' => 'E', 'Ĝ' => 'G', 'Ğ' => 'G',
    'Ġ' => 'G', 'Ģ' => 'G', 'Ĥ' => 'H', 'Ħ' => 'H', 'Ì' => 'I', 'Í' => 'I',
    'Î' => 'I', 'Ï' => 'I', 'Ī' => 'I', 'Ĩ' => 'I', 'Ĭ' => 'I', 'Į' => 'I',
    'İ' => 'I', 'IJ' => 'IJ', 'Ĵ' => 'J', 'Ķ' => 'K', 'Ł' => 'L', 'Ľ' => 'L',
    'Ĺ' => 'L', 'Ļ' => 'L', 'Ŀ' => 'L', 'Ñ' => 'N', 'Ń' => 'N', 'Ň' => 'N',
    'Ņ' => 'N', 'Ŋ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O',
    'Ö' => 'Oe', '&Ouml;' => 'Oe', 'Ø' => 'O', 'Ō' => 'O', 'Ő' => 'O', 'Ŏ' => 'O',
    'Œ' => 'OE', 'Ŕ' => 'R', 'Ř' => 'R', 'Ŗ' => 'R', 'Ś' => 'S', 'Š' => 'S',
    'Ş' => 'S', 'Ŝ' => 'S', 'Ș' => 'S', 'Ť' => 'T', 'Ţ' => 'T', 'Ŧ' => 'T',
    'Ț' => 'T', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'Ue', 'Ū' => 'U',
    '&Uuml;' => 'Ue', 'Ů' => 'U', 'Ű' => 'U', 'Ŭ' => 'U', 'Ũ' => 'U', 'Ų' => 'U',
    'Ŵ' => 'W', 'Ý' => 'Y', 'Ŷ' => 'Y', 'Ÿ' => 'Y', 'Ź' => 'Z', 'Ž' => 'Z',
    'Ż' => 'Z', 'Þ' => 'T', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a',
    'ä' => 'ae', '&auml;' => 'ae', 'å' => 'a', 'ā' => 'a', 'ą' => 'a', 'ă' => 'a',
    'æ' => 'ae', 'ç' => 'c', 'ć' => 'c', 'č' => 'c', 'ĉ' => 'c', 'ċ' => 'c',
    'ď' => 'd', 'đ' => 'd', 'ð' => 'd', 'è' => 'e', 'é' => 'e', 'ê' => 'e',
    'ë' => 'e', 'ē' => 'e', 'ę' => 'e', 'ě' => 'e', 'ĕ' => 'e', 'ė' => 'e',
    'ƒ' => 'f', 'ĝ' => 'g', 'ğ' => 'g', 'ġ' => 'g', 'ģ' => 'g', 'ĥ' => 'h',
    'ħ' => 'h', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ī' => 'i',
    'ĩ' => 'i', 'ĭ' => 'i', 'į' => 'i', 'ı' => 'i', 'ij' => 'ij', 'ĵ' => 'j',
    'ķ' => 'k', 'ĸ' => 'k', 'ł' => 'l', 'ľ' => 'l', 'ĺ' => 'l', 'ļ' => 'l',
    'ŀ' => 'l', 'ñ' => 'n', 'ń' => 'n', 'ň' => 'n', 'ņ' => 'n', 'ʼn' => 'n',
    'ŋ' => 'n', 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', 'ö' => 'oe',
    '&ouml;' => 'oe', 'ø' => 'o', 'ō' => 'o', 'ő' => 'o', 'ŏ' => 'o', 'œ' => 'oe',
    'ŕ' => 'r', 'ř' => 'r', 'ŗ' => 'r', 'š' => 's', 'ù' => 'u', 'ú' => 'u',
    'û' => 'u', 'ü' => 'ue', 'ū' => 'u', '&uuml;' => 'ue', 'ů' => 'u', 'ű' => 'u',
    'ŭ' => 'u', 'ũ' => 'u', 'ų' => 'u', 'ŵ' => 'w', 'ý' => 'y', 'ÿ' => 'y',
    'ŷ' => 'y', 'ž' => 'z', 'ż' => 'z', 'ź' => 'z', 'þ' => 't', 'ß' => 'ss',
    'ſ' => 'ss', 'ый' => 'iy', 'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G',
    'Д' => 'D', 'Е' => 'E', 'Ё' => 'YO', 'Ж' => 'ZH', 'З' => 'Z', 'И' => 'I',
    'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O',
    'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F',
    'Х' => 'H', 'Ц' => 'C', 'Ч' => 'CH', 'Ш' => 'SH', 'Щ' => 'SCH', 'Ъ' => '',
    'Ы' => 'Y', 'Ь' => '', 'Э' => 'E', 'Ю' => 'YU', 'Я' => 'YA', 'а' => 'a',
    'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'yo',
    'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k', 'л' => 'l',
    'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's',
    'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch',
    'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e',
    'ю' => 'yu', 'я' => 'ya'
];

echo str_replace(array_keys($replace), $replace, $string);  
person Dieter Gribnitz    schedule 04.07.2014
comment
самый быстрый способ, когда у вас много строк, например - person Bruno Pitteli Gonçalves; 19.03.2019

Начиная с PHP >= 5.4.0

$translatedString = transliterator_transliterate('Any-Latin; Latin-ASCII; [\u0080-\u7fff] remove', $string);
person woodscreative    schedule 08.02.2017

Строка $chain находится в той же кодировке символов, что и символы в массиве — возможно, даже вероятно, что строка $first_name находится в другой кодировке, и поэтому эти символы не совпадают. Вместо этого вы можете попробовать использовать многобайтовые строковые функции.

Попробуйте mb_convert_encoding. Вы также можете попробовать использовать HTML_ENTITIES в качестве параметра to_encoding, тогда вам не нужно беспокоиться о том, как будут преобразованы символы — это будет очень предсказуемо.

Предполагая, что вы вводите этот скрипт в UTF-8, возможно, неплохо начать...

$first_name = mb_convert_encoding($first_name, "HTML-ENTITIES", "UTF-8"); 
person Peter Bagnall    schedule 14.04.2012
comment
Я попробовал это, и это не так. эхо $first_name; // print áááááábééééééébšššš $first_name = mb_convert_encoding($first_name, HTML-ENTITIES, UTF-8); эхо $first_name; // печать - person Zoran Đukić; 14.04.2012
comment
Спасибо за ответ, проблема была в том, что я не добавил в форму accept-charset=UTF-8. - person Zoran Đukić; 14.04.2012

Жаль, что я нашел эту тему раньше. Функция, которую я сделал (которая заняла у меня слишком много времени), приведена ниже:

function CheckLetters($field){
    $letters = [
        0 => "a à á â ä æ ã å ā",
        1 => "c ç ć č",
        2 => "e é è ê ë ę ė ē",
        3 => "i ī į í ì ï î",
        4 => "l ł",
        5 => "n ñ ń",
        6 => "o ō ø œ õ ó ò ö ô",
        7 => "s ß ś š",
        8 => "u ū ú ù ü û",
        9 => "w ŵ",
        10 => "y ŷ ÿ",
        11 => "z ź ž ż",
    ];
    foreach ($letters as &$values){
        $newValue = substr($values, 0, 1);
        $values = substr($values, 2, strlen($values));
        $values = explode(" ", $values);
        foreach ($values as &$oldValue){
            while (strpos($field,$oldValue) !== false){
                $field = preg_replace("/" . $oldValue . '/', $newValue, $field, 1);
            }
        }
    }
    return $field;
}
person ChickenFeet    schedule 19.01.2016
comment
Это гениальный кусок кода. Особенно для поиска в базах данных с противоречивыми данными. Я использую его для поиска в базе данных страны, заполненной данными, предоставленными пользователем. Это действительно помогает не добавлять неправильно написанный пользовательский контент. Большой палец вверх от меня. - person Tom Groentjes; 10.11.2016
comment
Спасибо за ответ. Неправильно введенный пользовательский контент именно поэтому это и было написано :) - person ChickenFeet; 18.11.2016
comment
просто примечание, дополнительные начальные фигурные скобки в начале функции должны быть удалены, очевидно - person Rishiraj Purohit; 26.07.2017
comment
Хороший фрагмент кода, однако он не работает, если первый символ грязный. Попробуйте CheckLetters('åäö'); - person sboss; 28.11.2017
comment
@sboss спасибо, что указали на это. Был вызван while (strpos($field,$oldValue)), так как strpos возвращает 0, если символ найден в индексе 0 строки. Исправлено путем сравнения Not Identical. - person ChickenFeet; 29.11.2017
comment
Этот код превосходен и обеспечивает основу для добавления других проблемных символов по мере необходимости. Хорошее решение. - person Art Geigel; 09.07.2019

Способ CodeIgniter:

$this->load->helper('text');

$string = convert_accented_characters($string);

Эта функция использует сопутствующий конфигурационный файл application/config/foreign_chars.php для определения массива "в" и "из" для транслитерации.

https://www.codeigniter.com/user_guide/helpers/text_helper.html#ascii_to_entities

person alex iancu    schedule 19.11.2016
comment
1- Вопрос был задан более 2 лет назад 2- На вопрос есть принятый ответ. 3- ОП не упомянул CI Framework и использует обычный php, поэтому ваш ответ не имеет ничего общего с вопросом. пожалуйста, уделите больше внимания вопросам, прежде чем публиковать ответ - person EhsanT; 19.11.2016
comment
Это помогло мне после дня разочарования. Действительно хороший ответ для Codeigniter - person Crazy Developer; 20.06.2017
comment
@EhsanT 1. Возраст вопроса не имеет значения. На самом деле, этот сайт/ресурс приносит наибольшую пользу, когда люди вносят свой вклад в старый контент, а не ждут у входной двери, чтобы опубликовать повторяющиеся вопросы. 2. Принятый ответ не запрещает никому публиковать новый ответ. Людей никогда не следует удерживать от публикации после присуждения зеленой галочки. Хотя, вероятно, это не подходит для этого случая, зеленая галочка может передаваться. 3. ОП не нужно публиковать белый или черный список библиотек или фреймворков. Будущие исследователи могут использовать CI — этот ответ им поможет. - person mickmackusa; 21.09.2019
comment
Достаточно честно @mickmackusa. - person EhsanT; 24.09.2019

Простая функция. Преобразование строк типа «Ábç Éfg» в «abc_efg»

/**
 * @param $str
 * @return mixed
 */
function sanitizeString($str) {
    $str = preg_replace('/[áàãâä]/ui', 'a', $str);
    $str = preg_replace('/[éèêë]/ui', 'e', $str);
    $str = preg_replace('/[íìîï]/ui', 'i', $str);
    $str = preg_replace('/[óòõôö]/ui', 'o', $str);
    $str = preg_replace('/[úùûü]/ui', 'u', $str);
    $str = preg_replace('/[ç]/ui', 'c', $str);
    $str = preg_replace('/[^a-z0-9]/i', '_', $str);
    $str = preg_replace('/_+/', '_', $str);

    return $str;
}
person Jonas Elan    schedule 19.08.2019
comment
Это не держит дело. - person Toto; 20.08.2019