Objective-C какой-то особый символ, неуправляемо изменяющийся - PullRequest
0 голосов
/ 01 октября 2018

У меня есть строка, содержащая некоторые специальные символы (например, é, â, î, ı и т. Д.), Когда я использую подстроку в этой строке.Я сталкиваюсь с противоречивыми результатами.Некоторое специальное изменение символа бесконтрольно

enter image description here

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Вы предполагаете, что это все символы :

[newword substringWithRange:NSMakeRange(0,1)];    
[newword substringWithRange:NSMakeRange(1,1)];
[newword substringWithRange:NSMakeRange(2,1)];    
[newword substringWithRange:NSMakeRange(3,1)];
// and so on...

Другими словами, вы считаете, что:

  • A location всегда падаетв начале символа.
  • Символ всегда имеет length 1.

Оба предположения неверны.Пожалуйста, прочитайте главу «Персонажи и графемные кластеры» в Руководстве по программированию Apple ( здесь ).

Ваш é имеет длину 2, потому что это основабуква e, за которой следует , объединяющий диакритический акцент.Если вы хотите, чтобы он имел длину 1, вам нужно нормализовать строку перед ее использованием.Вызовите precomposedStringWithCanonicalMapping и используйте полученную строку.

Пример и доказательство (в Swift, но это не имеет значения, так как я использую NSString везде):

let s = "é,â,î,ı" as NSString
let c = s.substring(with: NSRange(location: 0, length: 1)) // e
let s2 = s.precomposedStringWithCanonicalMapping as NSString
let c2 = s2.substring(with: NSRange(location: 0, length: 1)) // é
0 голосов
/ 01 октября 2018

Вы рассматриваете строку в юникоде как последовательность байтов.Кодовые точки Unicode, кроме младшего UTF8, могут быть многобайтовыми, поэтому вы меняете стиль текста, удаляя части, отвечающие за ударение над буквой, как эта часть: https://www.compart.com/en/unicode/U+0301

UTF8 - это переменная ширина, поэтому путем обработкив качестве необработанных байтов вы можете получить странные результаты, я бы предложил использовать нечто, более осведомленное о юникоде, такое как ICU ( Международные компоненты для Юникода ).

Теперь представьте, что у вас есть двухбайтовая последовательностьвот так (это может быть не на 100% точно, но это иллюстрирует мою точку зрения):

0x056 0x000
  e    NUL

Теперь у вас есть строка UTF8 с 1 кодовой точкой и нулевым терминатором.Теперь скажите, что хотите добавить акцент к этому e.Как бы Вы это сделали?Вы можете использовать специальный код Unicode для изменения e, поэтому теперь строка выглядит так:

0x056 0x0CC 0x810 0x000
  e     U+0301     NUL

Где U+0301 - это 2-байтовый управляющий символ (Combining Acute Accent) и делает акцент e.


Редактировать: Ответ предполагает кодировку UTF8, что, скорее всего, неверное предположение, но я думаю, что ответ, будь то UTF8 или UTF16, или любой другой тип кодировки с управляющими символами,иллюстрирует, почему у вас могут быть таинственные исчезающие акценты.Хотя это может быть UTF16, для простоты давайте представим, что мы живем в мире, где жизнь немного лучше, потому что все используют только UTF8, а UTF16 не существует.


Для ответа на комментарий (это связано не столько с вопросом, но с некоторыми забавными мелочами) и с некоторыми забавными подробностями о времени выполнения NS / CF / Swift и мостах, а также о константах CF и прочих забавных вещах, подобных этому: представление фактической строки в памяти реализация определена и может варьироваться (даже для постоянных строк, поверьте мне, я знаю, я исправил реализацию ELF в Clang для CoreFoundation несколько дней назад).В любом случае, вот некоторый код:

CF_INLINE CFStringEncoding __CFStringGetSystemEncoding(void) {
    if (__CFDefaultSystemEncoding == kCFStringEncodingInvalidId) (void)CFStringGetSystemEncoding();
    return __CFDefaultSystemEncoding;
}

CFStringEncoding CFStringFileSystemEncoding(void) {
    if (__CFDefaultFileSystemEncoding == kCFStringEncodingInvalidId) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
        __CFDefaultFileSystemEncoding = kCFStringEncodingUTF8;
#else
        __CFDefaultFileSystemEncoding = CFStringGetSystemEncoding();
#endif
    }
    return __CFDefaultFileSystemEncoding;
}

В течение CoreFoundation / Foundation / SwiftFoundation (Да, вы никогда не знаете, какой тип NSString на самом деле тот, который вы держите, они обычно притворяются тем же, но подкапот в зависимости от того, как вы получили объект, который вы можете удерживать в одном из трех его вариантов).

Вот почему такой код существует, потому что строки NS / CF (Constant) / Swift имеют внутреннюю реализацию, определяемую реализациейпредставление.

if (((encoding & 0x0FFF) == kCFStringEncodingUnicode) && ((encoding == kCFStringEncodingUnicode) || ((encoding > kCFStringEncodingUTF8) && (encoding <= kCFStringEncodingUTF32LE)))) {

Если вы хотите согласованного поведения, вам нужно кодировать строку, используя определенную фиксированную кодировку, а не полагаться на внутреннее представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...