Как я могу определить или правильно определить длину странных символов? - PullRequest
0 голосов
/ 23 декабря 2011

Я вставляю мягкие дефисы в длинные слова программно, и у меня возникают проблемы с необычными символами, в частности: ■

Любое слово длиной более 10 символов обрабатывается мягкими дефисами.Слова определяются с помощью регулярного выражения: [A-Za-z0-9,.]+ (чтобы включить длинные числа).Если я разделю строку, содержащую два из указанных выше символов Юникода с этим регулярным выражением, я получу «слово», подобное этому: ■■

Мой сценарий затем просматривает каждое слово, измеряя длину (mb_strlen($word, 'UTF-8')),и если оно превышает произвольное количество символов, циклически перебирает буквы и вставляет мягкие дефисы повсюду (каждый третий символ, а не последние пять символов).

С ■■ - длина словавыходит достаточно высоко, чтобы вызвать замену (10).Таким образом, вставляются мягкие дефисы, но они вставляются в пределах символов.Итак, я получаю что-то вроде:

�­�■

В базе данных эти ■ символы хранятся (в блоке json_encoded) как "\ u2002", так что я могу видеть, куда идет длина строкиот.Что мне нужно, так это способ идентифицировать эти символы, чтобы я мог избежать добавления мягких дефисов к словам, которые их содержат.Любые идеи, кто-нибудь?

(Или это, или способ измерить длину строки, считая их как отдельные символы, а затем способ разбить эту строку на символы, не разделяя ее частично черезмногобайтовый символ.)

1 Ответ

1 голос
/ 23 декабря 2011

С теми же предостережениями, которые указаны в комментариях по поводу угадывания, не видя код:

mb_strlen($word, 'UTF-8'), и если оно превышает произвольное количество символов, циклически перебирает буквы

Я подозреваю, что вы действительно просматриваете байты. Это то, что произойдет, если вы используете обозначение доступа к массиву в строке.

Когда вы используете многобайтовую кодировку, такую ​​как UTF-8, буква (или, в более общем случае, «символ») может занимать более одного байта памяти. Если вы вставите или удалите середину последовательности байтов, вы получите искаженные результаты.

Вот почему вы должны использовать mb_strlen, а не просто старый strlen. Некоторые языки имеют собственный строковый тип Unicode, где каждый элемент является символом, но в PHP строки полностью основаны на байтах, и если вы хотите взаимодействовать с ними посимвольно, вы должны использовать функции mb_string . В частности, чтобы прочитать один символ из строки, вы используете mb_substr, и вы бы зациклили свой индекс от 0 до mb_strlen.

Вероятно, было бы проще взять совпавшее слово и использовать замену регулярного выражения для вставки мягкого дефиса между каждой последовательностью. Вы можете получить поддержку многобайтовых строк для регулярных выражений, используя флаг u. (Это работает только для UTF-8, но UTF-8 - единственная многобайтовая кодировка, которую вы когда-либо захотите использовать.)

const SHY= "\xC2\cAD"; // U+00AD Soft Hyphen encoded as UTF-8
$wrappableword= preg_replace('/.{3}\B/u', '$1'.SHY, $longword);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...