Нещодавно @javascript показав мені що окрім банального екранування данних потрібно думати ще і про UTF8 символи, якими можно надати тексту кастомний вигляд.
Не зміг знайти точної назви для такої техніки, але на сайтах-генераторах це звесться “текст символами”, або “генерація надписів із символів”, або “ASCII art”.
Для прикладу наведу один з генераторів:
До певного моменту ці символи виглядають прикольно, але коли ними зловживати то це ломає зовнішній вид інтерфейсу та створює враження що сайт зламаний.
Приклад:
Як боротися з ASCII-артом, якщо символи ломають зовнішний вигляд?
Правильна відповідь – треба обмежити використання UTF-8 символів. Залишити лише символи, які входять до алфафіту мови, цифри, пунктуацію та емоджі.
Можна використати регулярні вирази – ідеальний інструмент для роботи з текстом.
Задача виглядає простою. Але коли я почав експерементувати з текстом, виявилося що треба додати в “білий список” абсалютно всі символи котрими я користуюся, а ще потенційно багато симіолів про які я й не здогадуюсь, але вони все одно потрібні. Це забагацько роботи.
На допомогу приходять спеціальні Regex-групи UTF-8 символів. Для зручності симфоли згрупували та надали їм назви, тож їх тепер можно не описувати в Regex-виразі посимвольно, а просто вказати назву групи.
Які є групи Regex-символів?
Є основні групи UTF-8 символів котрі ще діляться на підгрупи. Далі йде список, який складається з двох рівнів. Перший рівень – велика група символів, підрівень – підгрупа символів.
\p{L}або\p{Letter}: будь-яка літера з будь-якої мови.\p{Ll}або\p{Lowercase_Letter}: мала літера, яка має варіант з великою.\p{Lu}або\p{Uppercase_Letter}: велика літера, яка має варіант малої.\p{Lt}або\p{Titlecase_Letter}: літера, яка з'являється на початку слова, коли з великої літери пишеться лише перша літера слова.\p{L&}або\p{Cased_Letter}: літера, яка існує у малих та великих регістрах (комбінація Ll, Lu та Lt).\p{Lm}або\p{Modifier_Letter}: спеціальний символ, який використовується як літера.\p{Lo}або\p{Other_Letter}: літера або ідеограма, яка не має малих і великих літер.
\p{M}або\p{Mark}: символ, призначений для поєднання з іншим символом (наприклад, наголоси, умляути, поля, що закривають, тощо).\p{Mn}або\p{Non_Spacing_Mark}: символ, призначений для поєднання з іншим символом без зайвого простору (наприклад, наголоси, умляути тощо).\p{Mc}або\p{Spacing_Combining_Mark}: символ, призначений для поєднання з іншим символом, який займає додатковий простір (голосні знаки у багатьох східних мовах).\p{Me}або\p{Enclosing_Mark}: символ, що охоплює символ, з яким він поєднується (коло, квадрат, клавіша тощо).
\p{Z}або\p{Separator}: будь-який пробіл або невидимий роздільник.\p{Zs}або\p{Space_Separator}: пробіл, який є невидимим, але займає місце.\p{Zl}або\p{Line_Separator}: символ-розділювач рядка U+2028.
\p{Zp}або\p{Paragraph_Separator}: символ-розділювач абзацу U+2029.
\p{S}або\p{Symbol}: математичні символи, грошові знаки, динбати, символи для малювання коробок тощо.\p{Sm}або\p{Math_Symbol}: будь-який математичний символ.\p{Sc}або\p{Currency_Symbol}: будь-який знак валюти.\p{Sk}або\p{Modifier_Symbol}: комбінований символ (знак) як повноцінний символ.\p{So}або\p{Other_Symbol}: різні символи, які не є математичними символами, знаками валют або комбінованими символами.
\p{N}або\p{Number}: будь-який цифровий символ у будь-якому шрифті.\p{Nd}або\p{Decimal_Digit_Number}: цифра від нуля до дев'яти будь-яким шрифтом, крім ідеографічних.\p{Nl}або\p{Letter_Number}: число, яке виглядає як літера, наприклад, римська цифра.\p{No}або\p{Other_Number}: надрядкова або підрядкова цифра, або число, яке не є цифрою 0-9 (за винятком чисел з ідеографічних шрифтів).
\p{P}або\p{Punctuation}: будь-який знак пунктуації.\p{Pd}або\p{Dash_Punctuation}: будь-який дефіс або тире.\p{Ps}або\p{Open_Punctuation}: будь-яка відкриваюча дужка.\p{Pe}або\p{Close_Punctuation}: будь-який тип закриваючої дужки.\p{Pi}або\p{Initial_Punctuation}: будь-який тип початкової лапки.\p{Pf}або\p{Final_Punctuation}: будь-яка закриваюча дужка.\p{Pc}або\p{Connector_Punctuation}: розділовий знак, наприклад, підкреслення, який з'єднує слова.\p{Po}або\p{Other_Punctuation}: будь-який розділовий знак, який не є тире, дужкою, лапкою або з'єднувачем.
\p{C}або\p{Other}: невидимі контрольні символи і невикористані кодові точки.\p{Cc}або\p{Control}: контрольний символ ASCII або Latin-1: 0x00-0x1F і 0x7F-0x9F.\p{Cf}або\p{Format}: невидимий індикатор форматування.\p{Co}або\p{Private_Use}: будь-яка точка коду, зарезервована для приватного використання.\p{Cs}або\p{Surrogate}: половина сурогатної пари у кодуванні UTF-16.\p{Cn}або\p{Unassigned}: будь-яка кодова точка, якій не призначено жодного символу.
Ще є додаткові групи, які спецефічні до конкретних мов, повний список можно переглянути на сторінці:
А як бути з Emoji? Як написати regex який буде відловлювати смайлики?
Нажаль, спеціальної regex-групи для Emoji поки не створено. В окремих реалізаціях Regex такі групи існують, але в PHP нажаль ні.
Тому нам потрібно самостійно описати номери UTF-8 символів які потім перетворяться на Emoji.
Я загуглив ці послідовності і просто залишу їх тут:
\x{1F600}-\x{1F64F}\x{2700}-\x{27BF}\x{1F680}-\x{1F6FF}\x{24C2}-\x{1F251}\x{1F30D}-\x{1F567}\x{1F900}-\x{1F9FF}\x{1F300}-\x{1F5FF}
Повний Regex для очистки тексту від небажаних UTF-8 символів виглядає так (код на PHP):
function sanitizeString(string $string) {
return preg_replace('/[^\p{L}\p{Z}\p{S}\p{N}\p{P}\p{C}\x{1F600}-\x{1F64F}\x{2700}-\x{27BF}\x{1F680}-\x{1F6FF}\x{24C2}-\x{1F251}\x{1F30D}-\x{1F567}\x{1F900}-\x{1F9FF}\x{1F300}-\x{1F5FF}]/u', '', $string);
}
Цей регулярний вираз залишає наступні символи:
- будь-які літери з будь-якої мови,
- будь-які пробіли або невидимі роздільники,
- математичні символи, грошові знаки, динбати, символи для малювання коробок тощо,
- будь-які цифрові символи у будь-якому шрифті,
- невидимі контрольні символи і невикористані кодові точки,
- будь-які знаки пунктуації,
- емоджі.
Інші символи вирізаються.
Висновок
Я розказав про актуальну проблему з UTF-8 символами, які ломають відображення тексту. Ми розібрали які групи UTF-8 символів існують, а на прикінці я поділився регулірним виразом для очистки UTF-8 текста від небажаних символів.
Сподіваюся, статя була інформативною і у вас є запитання – з ними у коментарі.
14 коментарів