Как корректно подсчитать длину строки, если в ней смесь кириллицы и латиницы?

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

Началось все с того, что функция вывода строки по центру стала себя плохо вести при выводе сообщений на русском языке.

Оказалось, что длина строки, вычисляемая через .lenght, не совпадает с реальным количеством знаков:

String msgEng =    "12345 Test message ";
String msgRus =    "Тестовое сообщение ";
String msgRusEng = "Тестовое 12message ";
void setup() 
{
  Serial.begin(9600);
  Serial.print("msgEng:"); Serial.println(msgEng.length());
  Serial.print("msgRus:"); Serial.println(msgRus.length());
  Serial.print("msgRusEng:"); Serial.println(msgRusEng.length());
}
void loop() 
{ }

Результат:

msgEng:19
msgRus:36
msgRusEng:27

 

com
Offline
Зарегистрирован: 06.09.2013

на русскую букву 2 байта.

а раньше было по другому?

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

Раньше не было необходимости использовать кириллицу, поэтому не знаю ;)

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

Сочинен вот такой код, который верно считает длину строки:

//char msg[] = "012345 Test message.";
  char msg[] = "012345 Пример текста";

void setup() 
{
  Serial.begin(9600);
  byte i,count=0;
  //Serial.println(msg); 
  while (msg[i] != '\0') 
  {
    //Serial.print((int)(msg[i])); // чтобы понять, как записывается символ "внутри"
    //Serial.print(" ");
    if (msg[i] < ' ') i=i+2;      // если кириллический символ, то проскакиваем следующий шаг
    else i++;
    count++;
  }
  Serial.print("\nCount:"); Serial.println(count);  
}

void loop() {}

Но... как-то это неоптимально, на мой взгляд. Есть ли менее ресурсоемкий способ?

Probelzaelo
Offline
Зарегистрирован: 15.04.2011

com пишет:

на русскую букву 2 байта.

а раньше было по другому?

Не понял, кто то в качестве редактора использует MSWord? без Unicode на символ = 1 байт. попробуйте свой текст выбросить на LCD, порадуетесь...

com
Offline
Зарегистрирован: 06.09.2013

то, что на экране символ занимает одно знакоместо совсем не означает, что это однобайтовый символ

maksim
Offline
Зарегистрирован: 12.02.2012

Probelzaelo пишет:

com пишет:

на русскую букву 2 байта.

а раньше было по другому?

Не понял, кто то в качестве редактора использует MSWord? без Unicode на символ = 1 байт. попробуйте свой текст выбросить на LCD, порадуетесь...

size_t LiquidCrystalRus::write(uint8_t value)
{
  uint8_t out_char=value;

  if (_dram_model == LCD_DRAM_WH1601) {  
    uint8_t ac=recv(LOW) & 0x7f;
    if (ac>7 && ac<0x14) command(LCD_SETDDRAMADDR | (0x40+ac-8));
  }

  if (value>=0x80) { // UTF-8 handling
    if (value >= 0xc0) {
      utf_hi_char = value - 0xd0;
    } else {
      value &= 0x3f;
      if (!utf_hi_char && (value == 1)) 
        send(0xa2,HIGH); // ╗
      else if ((utf_hi_char == 1) && (value == 0x11)) 
        send(0xb5,HIGH); // ╦
      else 
        send(pgm_read_byte_near(utf_recode + value + (utf_hi_char<<6) - 0x10), HIGH);
    }    
  } else send(out_char, HIGH);

  return 1; // assume sucess 
}

 

Probelzaelo
Offline
Зарегистрирован: 15.04.2011

Как то так, но в этом случае не мешало бы и остальные символы нарисовать. не очень понятно чем вообще обоснована затея держать в ардуине символы UTF? Разве что обрабатывать что то пришедшее с наружи... Но тогда было бы логично делать полную обработку, не ограничиваясь только кириллицей.

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

ребята, вы о чем? Мне нужно было выравнивать строку на LCD по центру, для этого было необходимо знать, сколько символов (физических знакомест) она занимает. Проблема решена - выражение .lenght заменено самописной функцией, пусть неоптимальной, но рабочей. :)

Probelzaelo
Offline
Зарегистрирован: 15.04.2011

Tomasina пишет:
Мне нужно было выравнивать строку на LCD по центру, для этого было необходимо знать, сколько символов (физических знакомест) она занимает. Проблема решена

"А мужики то не знают!"(с) ))

Впрочем, кроме одной задачи нашлись решения для сопутствующих...