Есть строка символов которая содержит произвольную мешанину латиницы/кириллицы Код (C++): void setup() { Serial.begin(115200); delay(2000); String S = "ZQПЕНЬ"; String S1; S1 = S.substring(0,6); Serial.print(S1); } Вернет ZQПЕ А вот: Код (C++): void setup() { Serial.begin(115200); delay(2000); String S = "ZQwmЕНЬ"; String S1; S1 = S.substring(0,6); Serial.print(S1); } } Вернет ZQwmЕ так как кириллица храниться в виде 2-х байт а латиница в виде одного. Какой оптимальный алгоритм можно применить, чтобы рассчитать правильно индекс для функции substring ? (например чтобы всегда возвращалось только первые 4 символа вне зависимости от того русские эти первые 4 буквы или английские)
В общем случае алгоритм будет довольно-таки сложным. Всё зависит от кодировки символов. Если брать простые 8-мибитные кодировки типа ASCII, KOI-8R и т.п., то в этом случае один символ -> один байт. А если брать Unicode и кодировки, используемые для него, например, UTF-8, то в этом случае всё печально. Дело в том, что русские символы не обязательно будут двух-байтовыми, хотя в подавляющем большинстве случаев это так. Например символ 'Ё' может быть закодирован как 'Ё' (U-0401), а может как пара символов 'Е' (U-0415) и '..' (U-0308). В последнем случае символ 'Ё' будет занимать четыре байта, но так почти ни когда не делают (ключевое слово -- "почти"). Но если хотите по-простому вычислять длину строки UTF-8 (именно эта кодировка используется в Arduino IDE), не заморачиваясь с комбинированными символами, то: если первый байт соответствует маске 0xxxxxxx, то символ одно-байтный; если первый байт соответствует маске 110xxxxx, то символ двух-байтный; если первый байт соответствует маске 1110xxxx, то символ трёх-байтный; если первый байт соответствует маске 11110xxx, то символ четырёх-байтный.
Именно так? Ничего другого? Китайщины там? Только латиница и кириллица? И ещё вопрос? Тебе это надо в Ардуино IDE или где?
Ну, вот для затравки, я сделал тебе substring (с одним параметром) как ты просил. Разбирайся. Спойлер: Код Код (C++): // // Определение класса "смешанная строка" // class MixedString : public String { static bool isCyrillic(const unsigned char c) { return c == 0xD0 || c == 0xD1; } public: MixedString(const char *cstr = "") : String(cstr) {} MixedString(const String &str) : String(str) {} MixedString substring( unsigned int beginIndex ) const; }; MixedString MixedString::substring(unsigned int beginIndex) const { unsigned int byteCounter = 0; for (uint16_t charCounter = 0; byteCounter < len && charCounter < beginIndex; charCounter++) { byteCounter += isCyrillic(buffer[byteCounter]) ? 2 : 1; } return String::substring(byteCounter); } // // Конец определения класса "смешанная строка" // ////////////////////////// void setup(void) { Serial.begin(115200); MixedString s = " ЖOПA "; // пробелы и буквы A и O - латинские for (int i = 0; i < 5; i++) { Serial.print("substring("); Serial.print(i); Serial.print(")=\""); Serial.print(s.substring(i)); Serial.println("\""); } } void loop(void) {} Спойлер: Результат Код (C++): substring(0)=" ЖOПA " substring(1)="ЖOПA " substring(2)="OПA " substring(3)="ПA " substring(4)="A " Как видишь, всё работает. Но, по уму тут надо доопределить и другие методы, типа charAt, setCharAt, operator [], length, ну и substring с двумя параметрами. Разумеется, также и все конструкторы - их там дохрена. Если разберёшься, как я тот сделал, то и эти сделаешь.
За пример спасибо! Хотя, мне собственно говоря нужна была функция, чтобы можно было обрезать конец строки, если она вдруг попадется слишком длинная.... Код (C++): String substringI (String S, uint8_t i) { uint8_t j = 0; while (i--) { j = j + bitRead(S.charAt(j), 7); j++; } return (S.substring(0, j)); } void setup() { Serial.begin(115200); String SJOPA = "ЖOПA_2020год"; for (int i = 1; i < 13; i++) { Serial.println(substringI(SJOPA,i)); } } void loop() { } Код (C++): Ж ЖO ЖOП ЖOПA ЖOПA_ ЖOПA_2 ЖOПA_20 ЖOПA_202 ЖOПA_2020 ЖOПA_2020г ЖOПA_2020го ЖOПA_2020год Ну вот.... как то так....