php lowercase utf 8
Сегодня разберем функцию strtolower, которая преобразует строку в нижний регистр. Т.е. все буквы делает строчными в php. Попробуем разобраться в ошибках связанных с функцией strtolower, примеры strtolower, напишем свою функцию для кириллицы преобразующие большие буквы в маленькие, но не только о strtolower, но и коснемся mb-strtolower.
Естественно нужно начать с определения даннйо функции:
Все о функции strtolower
Что такое strtolower
Синтаксис функции strtolower
Разбор синтаксиса функции strtolower
Использование strtolower:
Самое удобное, поместить в переменную текст, который пропускается через функцию и получается соответствующая строка.
Ну и далее оборачиваем переменную функцией strtolower:
И выводим результат с помощью echo
Пример использования strtolower для латиницы:
Далее применим к данной строке strtolower с использованием функции echo :
Результат применения strtolower к английскому тексту, который написан «ПРОПИСНЫМИ»
После этого можем переходить к кириллице!
Использование strtolower для кириллицы:
Опять поступаем со строкой, как в выше идущем пункте:
Расположим данный вывод прямо здесь и получим:
Мы видим, что ничего у нас не произошло…
Почему не сработала функция strtolower
Насколько я понимаю, что проблема в данном случае с кодировкой utf-8 для кириллицы! Дело в том, что кириллица в данной кодировке имеет не один символ а два. и strtolower просто не понимает, что от него хотят.
Чтобы показать в живую, чем отличается кириллица от латиницы:
Strtolower не работает для кириллицы
Но если например мы будем использовать данную функцию в таком виде:
То получим такой результат:
��� �������� �����, ������� ����� �������������� ��������� ���������� Чтобы mb_strtolower заработала с кириллицей UTF-8 ей нужно придать кодировку, таким образом:
Смотрим, что у нас в итоге получилось:
это тестовый текст, который будет иллюстрировать поведение стролловер
Собственная функция Strtolower для кириллицы!
Сталкивались с Strtolower для кириллицы!? Или может вы использовали mb-strtolower для кириллицы!? Эти функции работали и как впечатление!?
Когда в последний раз меня вывела из себя функция mb-strtolower – оказывается – эту хрень еще и подключать надо! Какая важная фифа, что она может даже быть и отключенная! Не то, что я не могу разобраться, как её включить – но просто это так достало, что просто нет тех слов цензурных слов, которые могли бы выразить все то, что я им хочу сказать!
Сделаем собственную функцию Strtolower для кириллицы!
Нам нужна такая функция Strtolower для кириллицы, чтобы она работала всегда и везде и чтобы больше никогда я не встречался с этой проблемой – мы просто напишем собственную функцию Strtolower для кириллицы!
Нам понадобится массив, который представляет из себя ключ – Большая кириллическая буква(верхний регистр = «ПРОПИСНЫЕ»), значение маленькая кириллическая буква(нижний регистр = «строчные»)
Еще нам понадобится функция strtr – которая преобразует найденные ключи в значения!
2). Поместим наш тестовый текст с прописными буквами в переменную
И обработаем дальше уже нашей функцией Strtolower для кириллицы
Результат работы собственной функции для кириллицы!
Собственная функция Strtolower для кириллицы и латиницы!
Пойдем дальше! Чем каждый раз вспоминать,какая функция работает там, работает сям! Сделаем функцию для кириллицы и латиницы, дарю:
Теперь давайте испытаем, сразу на двух текстах. что мы сделаем!?
Выведем наши текста таикм образом:
Результат работы собственной функции strollower
Онлайн функция Strtolower для текста!
Теперь на нашем сайте вы можете привести весь текст, который так или иначе написан с включением больших(прописных) букв, превратить в текст написанный строчными, т.е. маленькими!
Как работает онлайн Strtolower
В поле ввода пишем или вставляем текст ПРОПИСНЫМИ! И нажимаем отправить! И вы получите результат! Пока только Русский и английский языки!
Сообщение системы комментирования :
Форма пока доступна только админу. скоро все заработает. надеюсь.
strtolower
(PHP 4, PHP 5, PHP 7, PHP 8)
strtolower — Преобразует строку в нижний регистр
Описание
Принадлежность того или иного символа к буквенным определяется с учётом текущей локали. Это означает, что, например, в используемой по умолчанию локали «C», символ Ä не будет преобразован.
Список параметров
Возвращаемые значения
Возвращает строку в нижнем регистре.
Примеры
Пример #1 Пример использования strtolower()
Примечания
Замечание: Эта функция безопасна для обработки данных в двоичной форме.
Смотрите также
User Contributed Notes 16 notes
strtolower(); doesn’t work for polish chars
for cyrillic and UTF 8 use mb_convert_case
//output is: австралия
?>
the function arraytolower will create duplicate entries since keys are case sensitive.
I prefer this method
Array
(
[test1] => asgafasdaad
[TEST2] => asddhshsdgb
[TeSt3] => asdasda@asdadadasdasdgh
)
Array
(
[test1] => asgafasdaad
[test2] => asddhshsdgb
[test3] => asdasda@asdadadasdasdgh
)
echo fullLower ( «Ã É Ò Õ ÚÙÛ» );
//results ã é ò õ úùû
//adapted from fullUpper on strtoupper manual
?>
When you’re not sure, how the current locale is set, you might find the following function useful. It’s strtolower for utf8-formatted text:
If you’re considering using the below unhtmlentities function from phpContrib, I would suggest this one as an alternative:
There’s a ucfirst «function» to make the first character uppercase, but there’s no «lcfirst» function to make the first character lowercase. Here’s my own code to accomplish this.
I found this particularly useful for generating XML nodes with the Reflection class.
Heres a small function I wrote to stop people from submitting data that is ALL IN CAPS SO THEY CAN GET MORE ATTENTION THAT THE REST OF THE USER SUBMITTED DATA on my website 🙂 If you can make it better, by all means do so. This function splits up words delimited by a space, and makes only the first letter of each word capitalized. You can easily modify it so it’s only the very first word of the string. I’ve also added some exceptions so you don’t make things like roman numerals look like «Iii» or «Xcmii» or something.
function RemoveShouting($string)
<
$lower_exceptions = array(
«to» => «1», «a» => «1», «the» => «1», «of» => «1»
);
$higher_exceptions = array(
«I» => «1», «II» => «1», «III» => «1», «IV» => «1»,
«V» => «1», «VI» => «1», «VII» => «1», «VIII» => «1»,
«XI» => «1», «X» => «1»
);
To do case insensitive comparisons in a database, strtolower() can be a quick and dirty solution:
$Sql = «SELECT * FROM tablename WHERE LOWER(column_name) = ‘».strtolower($my_var).»‘»;
the strtolower version to support most amount of languages including russian, french and so on:
To convert an entire array to lower, I prefer this method;
If you ever need to strtolower a string with href tags on it and doesn’t want to mess with the characters inside a tag, this is for you.
?>
this:
echo loweroutsidetags(‘aALalala ‘)
Функции для работы с многобайтовыми строками
Схемы многобайтного кодирования символов и их реализации достаточно сложны, и их описание находится за пределами этой документации. Более исчерпывающую информацию о кодировках и их устройстве можно почерпнуть из нижеприведённых источников.
Материалы по Юникоду
Информация о символах японской/корейской/китайской кодировок
Содержание
User Contributed Notes 35 notes
Please note that all the discussion about mb_str_replace in the comments is pretty pointless. str_replace works just fine with multibyte strings:
= ‘漢字はユニコード’ ;
$needle = ‘は’ ;
$replace = ‘Foo’ ;
?>
The usual problem is that the string is evaluated as binary string, meaning PHP is not aware of encodings at all. Problems arise if you are getting a value «from outside» somewhere (database, POST request) and the encoding of the needle and the haystack is not the same. That typically means the source code is not saved in the same encoding as you are receiving «from outside». Therefore the binary representations don’t match and nothing happens.
PHP can input and output Unicode, but a little different from what Microsoft means: when Microsoft says «Unicode», it unexplicitly means little-endian UTF-16 with BOM(FF FE = chr(255).chr(254)), whereas PHP’s «UTF-16» means big-endian with BOM. For this reason, PHP does not seem to be able to output Unicode CSV file for Microsoft Excel. Solving this problem is quite simple: just put BOM infront of UTF-16LE string.
SOME multibyte encodings can safely be used in str_replace() and the like, others cannot. It’s not enough to ensure that all the strings involved use the same encoding: obviously they have to, but it’s not enough. It has to be the right sort of encoding.
UTF-8 is one of the safe ones, because it was designed to be unambiguous about where each encoded character begins and ends in the string of bytes that makes up the encoded text. Some encodings are not safe: the last bytes of one character in a text followed by the first bytes of the next character may together make a valid character. str_replace() knows nothing about «characters», «character encodings» or «encoded text». It only knows about the string of bytes. To str_replace(), two adjacent characters with two-byte encodings just looks like a sequence of four bytes and it’s not going to know it shouldn’t try to match the middle two bytes.
While real-world examples can be found of str_replace() mangling text, it can be illustrated by using the HTML-ENTITIES encoding. It’s not one of the safe ones. All of the strings being passed to str_replace() are valid HTML-ENTITIES-encoded text so the «all inputs use the same encoding» rule is satisfied.
The text is «x = ‘x ;
mb_internal_encoding ( ‘HTML-ENTITIES’ );
?>
Even though neither ‘l’ nor ‘;’ appear in the text «x y» and in the other it broke the encoding completely.
One more reason to use UTF-8 if you can, I guess.
Yet another single-line mb_trim() function
PHP5 has no mb_trim(), so here’s one I made. It work just as trim(), but with the added bonus of PCRE character classes (including, of course, all the useful Unicode ones such as \pZ).
UTF-8 в PHP. Часть 1
1. Вступление
Для понимания дальнейшего текста начинающим нужно знать некоторые детали по кодировкам в целом. Подачу материала я постараюсь максимально упростить. Для незнающих ничего о побитовых операциях необходимо предварительно ознакомиться с материалами на википедии.
Начать нужно с понимания того, что компьютер работает с числами и хранить строку (и символ, как её часть) приходиться тоже в числовом виде. Для этих целей существуют кодировки. По сути это таблицы, в которых указано соответствие между числами и символами. Исторически сложилось, что основная кодировка ASCII содержит лишь контрольные коды и латинские символы, всего их 128 (127 – максимальное число, которое можно хранить в 7 битах).
Для того чтобы хранить и другие тексты на основе ASCII было создано много других кодировок, в которых добавили 8-ой бит. Они могут хранить уже до 256 символов, первые 128 с которых традиционно соответствовали ASCII, а вот в остальную часть каждый пихал всё, что ему хотелось. Так и получилось, что у каждого производителя операционных систем свои наборы кодировок, причём каждая удовлетворяла потребности лишь относительно узкого круга людей. Ситуацию ещё сильнее усложнили отсутствием общих стандартов, различать их алгоритмически стало невозможно и теперь это больше похоже на угадывание (об этом в следующих частях).
В итоге потребовался универсальный выход, кодировка, которая сможет хранить все возможные символы и будет учитывать различия в письме различных народов (например, направление письма). Поставленную задачу решили созданием Unicode, которая способна кодировать практически все системы письменности в мире одной кодировкой.
Хотелось бы подробнее остановиться на последнем пункте. Это значит, что если раньше можно было выполнять простое преобразование по таблице и записывать результат, то сейчас определён и метод сохранения этого результата, в зависимости от разрядности, которая требуется для его хранения. На примере принцип хранения вы можете увидеть в таблице (x – хранимые биты данных):
Бит | Максимальное хранимое значение | 1 октет | 2 октет | 3 октет | 4 октет |
---|---|---|---|---|---|
Начальный октет | Продолжающие октеты | ||||
7 | U+007F | 0xxxxxxx | |||
11 | U+07FF | 110xxxxx | 10xxxxxx | ||
16 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
21 | U+10FFFF (по стандарту, но реально U+1FFFFF) | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
Легко заметить, что в старших битах начального октета всегда находится счётчик, указывающий на количество байт в последовательности – это количество ведущих единиц, после которых идёт ноль. Обратите внимание: если октет лишь один, то ведущая единица не указывается, благодаря чему начальные октеты легко отличить от продолжающих.
Для примера давайте посмотрим как строка «Привет Hi» будет выглядеть в кодировке UTF-8.
Шаг первый. Перевести каждый символ в его числовое представление (я буду использовать шестнадцатеричную систему исчисления) по таблице.
Привет Hi = 0x041F 0x0440 0x0438 0x0432 0x044D 0x0442 0x0020 0x0048 0x0069
Не забываем, что пробел – тоже символ.
Шаг второй. Конвертировать числа из шестнадцатеричной в двоичную систему. Используем калькулятор Windows 7 (в режиме программиста).
0x041F = 0000 0100 0001 1111
0x0440 = 0000 0100 0100 0000
0x0438 = 0000 0100 0011 1000
0x0432 = 0000 0100 0011 0010
0x0435 = 0000 0100 0011 0101
0x0442 = 0000 0100 0100 0010
0x0020 = 0010 0000
0x0048 = 0100 1000
0x0069 = 0110 1001
Для наглядности я добавил нули в старшие разряды. Обратите внимание: символы могут занимать разное количество байт.
Шаг третий. Перевести числовые представления в последовательности октетов UTF-8.
0x041F = 100 0001 1111 = 110xxxxx 10xxxxxx = 11010000 10011111
0x0440 = 100 0100 0000 = 110xxxxx 10xxxxxx = 11010001 10000000
0x0438 = 100 0011 1000 = 110xxxxx 10xxxxxx = 11010000 10111000
0x0432 = 100 0011 0010 = 110xxxxx 10xxxxxx = 11010000 10110010
0x0435 = 100 0011 0101 = 110xxxxx 10xxxxxx = 11010000 10110101
0x0442 = 100 0100 0010 = 110xxxxx 10xxxxxx = 11010001 10000010
0x0020 = 010 0000 = 0xxxxxx = 00100000
0x0048 = 100 1000 = 0xxxxxx = 01001000
0x0069 = 110 1001 = 0xxxxxx = 01101001
Счётчики выделены жирным. Обратите внимание: символы с кодами до 0x0080 сохраняются без изменений, это и есть совместимость с ASCII. Ещё следует понимать, что UTF-8 будет занимать в 2 раза больше места (2 байта) для русскоязычного текста, чем Windows-1251, которая использует лишь 1 байт.
В качестве решения можно записать всю последовательность подряд (надеюсь без ошибок): «11010000 10011111 11010001 10000000 11010000 10111000 11010000 10110010 11010000 10110101 11010001 10000010 00100000 01001000 01101001».
Проверить решение можно кодом:
Оптимизированный PHP код, который позволяет получать числовое представление символов и обратную операцию (полную версию опубликую в конце цикла):
Метод getChar() был взят с библиотеки Jevix, я всё-равно уже видел этот код, хорошо его запомнил и даже при его реализации по памяти было бы нечестно не упомянуть автора.
Вы же можете протестировать получившийся класс при помощи кода:
Я не старался писать самый красивый или правильный код для тестов, но при помощи него вы можете спокойно побитово менять значения символов и сразу видеть результат. Все невалидные последовательности будут проигнорированы, выводимая строка всегда валидна, но это ещё далеко не всё.
Чтобы быть уверенным, что текст не содержит ничего лишнего нужно удалить с него ненужные (непечатные, нарушающие разметку, неопределённые, суррогатные и т.п.) символы и провести нормализацию, об этом в следующей части.
Дальше будет про нормализацию, безопасность, определение кодировок и работу с UTF-8 в PHP.
Определение кодировки текста в PHP — обзор существующих решений плюс еще один велосипед
Столкнулся с задачей — автоопределение кодировки страницы/текста/чего угодно. Задача не нова, и велосипедов понапридумано уже много. В статье небольшой обзор найденного в сети — плюс предложение своего, как мне кажется, достойного решения.
Если кратко — он не работает.
Давайте смотреть:
Как видим, на выходе — полная каша. Что мы делаем, когда непонятно почему так себя ведет функция? Правильно, гуглим. Нашел замечательный ответ.
Чтобы окончательно развеять все надежды на использование mb_detect_encoding(), надо залезть в исходники расширения mbstring. Итак, закатали рукава, поехали:
Постить полный текст метода не буду, чтобы не засорять статью лишними исходниками. Кому это интересно посмотрят сами. Нас истересует строка под номером 593, где собственно и происходит проверка того, подходит ли символ под кодировку:
Вот основные фильтры для однобайтовой кириллицы:
Windows-1251 (оригинальные комментарии сохранены)
ISO-8859-5 (тут вообще все весело)
Как видим, ISO-8859-5 всегда возвращает TRUE (чтобы вернуть FALSE, нужно выставить filter->flag = 1).
Когда посмотрели фильтры, все встало на свои места. CP1251 от KOI8-R не отличить никак. ISO-8859-5 вообще если есть в списке кодировок — будет всегда детектиться как верная.
В общем, fail. Оно и понятно — только по кодам символов нельзя в общем случае узнать кодировку, так как эти коды пересекаются в разных кодировках.
2. Что выдает гугл
А гугл выдает всякие убожества. Даже не буду постить сюда исходники, сами посмотрите, если захотите (уберите пробел после http://, не знаю я как показать текст не ссылкой):
http:// deer.org.ua/2009/10/06/1/
http:// php.su/forum/topic.php?forum=1&topic=1346
3. Поиск по хабру
2) на мой взгляд, очень интересное решение: habrahabr.ru/blogs/php/27378/#comment_1399654
Минусы и плюсы в комменте по ссылке. Лично я считаю, что только для детекта кодировки это решение избыточно — слишком мощно получается. Определение кодировки в нем — как побочный эффект ).
4. Собственно, мое решение
Идея возникла во время просмотра второй ссылки из прошлого раздела. Идея следующая: берем большой русский текст, замеряем частоты разных букв, по этим частотам детектим кодировку. Забегая вперед, сразу скажу — будут проблемы с большими и маленькими буквами. Поэтому выкладываю примеры частот букв (назовем это — «спектр») как с учетом регистра, так и без (во втором случае к маленькой букве добавлял еще большую с такой же частотой, а большие все удалял). В этих «спектрах» вырезаны все буквы, имеющие частоты меньше 0,001 и пробел. Вот, что у меня получилось после обработки «Войны и Мира»:
Спектры в разных кодировках (ключи массива — коды соответствующих символов в соответствующей кодировке):
Далее. Берем текст неизвестной кодировки, для каждой проверяемой кодировки находим частоту текущего символа и прибавляем к «рейтингу» этой кодировки. Кодировка с бОльшим рейтингом и есть, скорее всего, кодировка текста.
Результаты
У-упс! Полная каша. А потому что большие буквы в CP1251 обычно соответствуют маленьким в KOI8-R. А маленькие буквы используются в свою очередь намного чаще, чем большие. Вот и определяем строку капсом в CP1251 как KOI8-R.
Пробуем делать без учета регистра («спектры» case insensitive)
Как видим, верная кодировка стабильно лидирует и с регистрозависимыми «спектрами» (если строка содержит небольшое количество заглавных букв), и с регистронезависимыми. Во втором случае, с регистронезависимыми, лидирует не так уверенно, конечно, но вполне стабильно даже на маленьких строках. Можно поиграться еще с весами букв — сделать их нелинейными относительно частоты, например.
5. Заключение
В топике не расмотрена работа с UTF-8 — тут никакий принципиальной разницы нету, разве что получение кодов символов и разбиение строки на символы будет несколько длиннее/сложнее.
Эти идеи можно распространить не только на кириллические кодировки, конечно — вопрос только в «спектрах» соответствующих языков/кодировок.
P.S. Если будет очень нужно/интересно — потом выложу второй частью полностью работающую библиотеку на GitHub. Хотя я считаю, что данных в посте вполне достаточно для быстрого написания такой библиотеки и самому под свои нужды — «спектр» для русского языка выложен, его можно без труда перенести на все нужные кодировки.
UPDATED
В комментариях проскочила замечательная функция, ссылку на которую я опубликовал под графом «убожество». Может быть погорячился со словами, но уж как опубликовал, так опубликовал — редактировать такие вещи не привык. Чтобы не быть голословным, давайте разберемся, работает ли она на 100%, как об этом говорит предполагаемый автор.
1) будут ли ошибки при «нормальной» работе этой функции? Предположим, что контент у нас на 100% валидный.
ответ: да, будут.
2) определит ли она что-нибудь кроме UTF-8 и не-UTF-8?
ответ: нет, не определит.