php mb_convert_case () сохраняет слова в верхнем регистре - PullRequest
3 голосов
/ 21 июля 2010

Предполагается, что у меня есть строка "Текстовая строка HET1200", и мне нужно изменить ее на "Текстовая строка HET1200" Кодировка будет UTF-8.

Как я могу это сделать? В настоящее время я использую mb_convert_case($string, MB_CASE_TITLE, "UTF-8");, но это меняет "HET1200" на "Het1200.

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

Спасибо:)

1 Ответ

4 голосов
/ 26 июля 2010

ОК, давайте попробуем воссоздать mb_convert_case как можно ближе, но изменив только первый символ каждого слова.

Соответствующая часть реализации mb_convert_case такова:

int mode = 0; 

for (i = 0; i < unicode_len; i+=4) {
    int res = php_unicode_is_prop(
        BE_ARY_TO_UINT32(&unicode_ptr[i]),
        UC_MN|UC_ME|UC_CF|UC_LM|UC_SK|UC_LU|UC_LL|UC_LT|UC_PO|UC_OS, 0);
    if (mode) {
        if (res) {
            UINT32_TO_BE_ARY(&unicode_ptr[i],
                php_unicode_tolower(BE_ARY_TO_UINT32(&unicode_ptr[i]),
                    _src_encoding TSRMLS_CC));
        } else {
            mode = 0;
        }   
    } else {
        if (res) {
            mode = 1;
            UINT32_TO_BE_ARY(&unicode_ptr[i],
                php_unicode_totitle(BE_ARY_TO_UINT32(&unicode_ptr[i]),
                    _src_encoding TSRMLS_CC));
        }
    }
}

В основном это делает следующее:

  • Установите mode на 0. mode определит, находимся ли мы в первом знаке слова. Если это 0, мы, в противном случае, мы не.
  • Перебирать символы строки.
    • Определите, что это за персонаж.
      • Установите res на 1, если это символ слова. В частности, установите его на 1, если он имеет свойства «Пометить, без пробелов», «Пометить, заключить», «Другое, Формат», «Буква, Модификатор», «Символ, Модификатор», «Буква, Прописные »,« Буквы, строчные буквы »,« Буквы, заглавные буквы »,« Знаки пунктуации, другие »или« Другие, суррогатные ». Как ни странно, «Письмо, Другое» не входит.
    • Если мы не в начале слова
      • Если мы находимся в символе слова, конвертируем его в нижний регистр - это то, что нам не нужно .
      • В противном случае мы не находимся на символе слова, и мы устанавливаем mode в 0, чтобы сигнализировать о том, что мы движемся к началу слова.
    • Если мы в начале слова и у нас действительно есть слово
      • Преобразовать этот символ в заглавный регистр
      • Сигнал, что мы больше не в начале слова.

Расширение mbstring, похоже, не раскрывает свойства персонажа. Это оставляет нас с проблемой, потому что у нас нет хорошего способа определить, имеет ли персонаж какое-либо из 10 свойств, для которых mb_convert_case проверяет.

К счастью, свойства символов Юникода в регулярном выражении могут спасти нас здесь.

Точное воспроизведение mb_convert_case с проблемным преобразованием в нижний регистр становится:

function mb_convert_case_utf8_variation($s) {
    $arr = preg_split("//u", $s, -1, PREG_SPLIT_NO_EMPTY);
    $result = "";
    $mode = false;
    foreach ($arr as $char) {
        $res = preg_match(
            '/\\p{Mn}|\\p{Me}|\\p{Cf}|\\p{Lm}|\\p{Sk}|\\p{Lu}|\\p{Ll}|'.
            '\\p{Lt}|\\p{Sk}|\\p{Cs}/u', $char) == 1;
        if ($mode) {
            if (!$res)
                $mode = false;
        }
        elseif ($res) {
            $mode = true;
            $char = mb_convert_case($char, MB_CASE_TITLE, "UTF-8");
        }
        $result .= $char;
    }

    return $result;
}

Тест:

echo mb_convert_case_utf8_variation("HETÁ1200 Ááxt ítring uii");

дает:

HETÁ1200 Ááxt Ítring Uii
...