json и кирилица

Экспериментируя с json и xmlhttprequest обнаружилась неочевидная проблема -как передать кирилицу? json парсится как utf-8 шо нифига не бъется с win-1251 и явных решений в инете как обычно найдено не было, т.к. все кодят на php и в базах данных, а у меня маленький сервер на Си и веб на javascript. После нескольких дней упорного перетыкания javascript функций декодирования стало понятно, что однобайтовой кодировкой это все не решается и необходимо все это перекодировать в юникод да еще и обрабатывать от escape последовательностей чтобы были буквы а не цифры.
Итого json ответ:

Что видим:


Код сервака:

const char *ucs[]={"\\u0410", "\\u0411","\\u0412","\\u0413","\\u0414","\\u0415",
		"\\u0416","\\u0417","\\u0418","\\u0419","\\u041a","\\u041b","\\u041c","\\u041d","\\u041e",
		"\\u041f","\\u0420","\\u0421","\\u0422","\\u0423","\\u0424","\\u0425","\\u0426","\\u0427",
		"\\u0428","\\u0429","\\u042a","\\u042b","\\u042c","\\u042d","\\u042e","\\u042f","\\u0430",
		"\\u0431","\\u0432","\\u0433","\\u0434","\\u0435","\\u0436","\\u0437","\\u0438","\\u0439",
		"\\u043a","\\u043b","\\u043c","\\u043d","\\u043e","\\u043f","\\u0440","\\u0441","\\u0442",
		"\\u0443","\\u0444","\\u0445","\\u0446","\\u0447","\\u0448","\\u0449","\\u044a","\\u044b",
		"\\u044c","\\u044d","\\u044e","\\u044f","\\u0450","\\u0451"};

 void encode_ucs2(char * value, char *ucs_string)
 {
 	//Для символов латиницы просто добавляется 00h. Для символов кириллицы (от C0h до FFh - в кодировке Windows)
 		//можно использовать такое правило: из байта вычитается C0h и прибавляется 410h
 		//		(кроме букв "ё" и "Ё", коды которых - 0451h и 0410h)

	 uint16_t val;
 		int i,k,l;
 		k=strlen(value);
 		ucs_string[0]=0;

 	for(i=0;i<k;i++)
 	{
 		 if((unsigned char)value[i]>=0xC0)
 		 {
 		  val=(unsigned char)value[i]-0xC0;
 		   strcat(ucs_string,ucs[val]);
 		 }
 		 else
 		 {
 			l=strlen(ucs_string);
 			ucs_string[l]=value[i];
 			ucs_string[l+1]=0;
 		 }
 	}

 }

При обработке в javascript надо применить функцию unescape() чтобы были буквы например так:

 description=unescape( юникод строка);

И небольшое объявление:
Если кого то заинтересовала КДПВ с веб мордой и есть серьезное желание принять участие в переделке этого в опенсорс дайте мне знать (а заодно подтянуть меня в плане программирования ;) ).
  • +1
  • 19 июня 2015, 12:21
  • GYUR22

Комментарии (47)

RSS свернуть / развернуть
Из разряда «Всё украдено до нас» libiconv.
Если дело под виндой, то можно извратнуться MultiByteToWideCharWideCharToMultiByte, или более скучное TranslateCharsetInfo.
Ну а так-то да, все колхозят своё.
0
ну МК это не винда, насчет libiconv нифига не понял — вынос мозга,
а по свое у меня вроде проще получилось.
0
А, ну раз мк, тогда «Content-Type: application/json; charset=windows-1251» вас спасет. Не по феншую, но проблем не наблюдал пока.
0
спасибо проверю (просто где то мелькало что это не помогает)
0
Спасибо, работает!
0
вроде как jQuery проблемы изначально не имеет, как и куча либ. а голый js… простите, но моветон
0
  • avatar
  • xar
  • 19 июня 2015, 15:31
ну как бэ jquery не лез в мк…, а так наверное да.
0
дык если уж за jQuery пошло, то ему и не надо в мк лезть, достаточно ссылку на него вписать хоть с разрабов, хоть с яндекса/гугла. Данные все равно ж пади через инет бегают.
0
вводная: инет есть не везде, устройство самодостаточное.
+1
простите конечно, но 1 — про мк в статье прям ну очень много написано, про автономность тоже практически достаточно. как же мы это проглядели…
0
Внешние зависимости в любом случае втыкать следует только при крайней необходимости.
0
это норма.
0
Подход-то правильный, но код жуткий.
0
нежуткий код в студию!
0
strlen/strcat по всему буферу в цикле — вообще ужос (понятно, что на какую-то там десятикратную потерю эффективности на пустом месте сейчас всем насрать, но и просто для глазу должно быть неприятно).
Итерация по строке тоже в Си делается проще, эффективней и красивей, чем циклом с индексом…
Ну и в целом, нафига писать завершающий ноль в каждой итерации? Опять же, вопрос не столько эффективности, сколько простой логичности.

#define ENCODE_UCS2_SIZE    6

void encode_ucs2(char *buf, char *str)
{
    char *p, *dst/*, *tmp*/;
    unsigned char c;

    dst = buf;

    for(p = str; *p != 0; p++)
    {
        c = *p;
    
        if(c >= 0xC0)
        {
            /* можно и так, но не нужно */
            /*tmp = ucs[c - 0xC0];
            strcpy(dst, tmp);
            dst += strlen(tmp);*/
            
            memcpy(dst, ucs[c - 0xC0], ENCODE_UCS2_SIZE);
            dst += ENCODE_UCS2_SIZE;
        }
        else
        {
            *(dst++) = c;
        }
    }

    *dst = 0;
}
0
Да конечно так моднее :) спасибо за пример.
0
if((unsigned char)value[i]>=0xC0)

Получается вы игнорируете буквы Ё, ё ибо их коды в win-1251 равны 0xa8, 0xb8?

Я бы тогда реализовывал без таблицы, как-то так

#define WIN1251RUS_OFFSET 0xC0
#define UTF8RUS_OFFSET 0x410

void encode_ucs2(const char *win_str, char *utf_str) {
	static const char * hex = "0123456789abcdef";

	while(*win_str != 0) {

		uint_8t c = *win_str;
		if(c >= WIN1251RUS_OFFSET) {
			uint_16t u = c - WIN1251RUS_OFFSET + UTF8RUS_OFFSET;

			*utf_str++ = '\\';
			*utf_str++ = 'u';
			*utf_str++ = hex[(u >> 12) & 0x0F];
			*utf_str++ = hex[(u >> 8) & 0x0F];
			*utf_str++ = hex[(u >> 4) & 0x0F];
			*utf_str++ = hex[u & 0x0F];

		} else {
			*utf_str++ = c;
		}

		win_str++;
	}

	*utf_str = 0;
}

Хотя лучше добавить обработку символов с кодами от 0x80 до 0xC0, или, хотя бы, Ё, ё и (для гарантии) проверку переполнения буфера приемника
0
у меня win-1251 строка ограничена сама по себе 20-ю символами поэтому мне переполнение в буфере на 128 символов не грозит.
0
Это сегодня. А завтра ситуация может внезапно измениться. И вообще, у французов от этой херни ариан упал!)
+2
тогда конечно ;)
0
И вообще, у французов от этой херни ариан упал!)
Да, это показательный пример. Но пример не столько ошибки в реализации, сколько ошибки в методологии.
0
Так и здесь аналогично.
0
Вот ни разу не понимаю, нафига вообще пользоваться Win-1251 (за этого уродца мелкомягким вообще надо бы оторвать некоторые части тела, что бы не размножались). Не проще ли перейти полностью на UTF-8 и забыть о головняке и перекодировках?
0
win-1251 компактней, быстрее и удобней.
0
win-1251 компактней
Только для текста на русском, которого на страничках из топика совсем не так много.
быстрее
С перекодировками — медленнее.
удобней
Чем?
0
На страничках — мб, а вообще — компактней.
Unicode — в принципе говно. Со всем этим адом связываться только в самом крайнем случае.
0
На страничках — мб, а вообще — компактней.
Ровно до тех пор, пока там будет исключительно текст влезающий в 1251 (а набор там весьма скуден). Если учесть, что использованные технологии (HTTP+HTML+JS) не накладывают таких ограничений, выбор кодировки, с которой надо а) трахаться что бы перекодировать, и б) которая накладывает ограничения — выглядит, мягко говоря не логичным.
Unicode — в принципе говно.
Вы или не порите чушь или придумайте что-то лучше, чем юникод. Искренне желаю вам удачи в этом процессе.
Со всем этим адом связываться только в самом крайнем случае.
Если с этим адом связаться в однобайтовых кодировках, то юникодные приколы покажутся несущественными мелочами. К тому же все, что там перечислено а) никак не касается кириллицы (а используя 1251 именно ею вы и ограничены) и б) давно учтены во всевозможных библиотеках (так что заморачиваться самостоятельно имеет смысл только из мазохизма). А сама статься просто отличный перечень аргументов для того, чтобы не изобретать велосипед и взять готовое. Хотя я подозреваю, что на мазохистов такая аргументация не подействует.
0
Обычно надо кириллицу и ничего лишнего. Зачем разбираться какая либа какие приколы учитывает (полагаю, жабий язык нативно их едва ли умеет...)? Или думать как избавиться от лишнего, если не хочется тащить за программкой/прошивкой мегабайты ненужного кода.
Надо понимать, что если нужно забить гвоздь, иногда можно просто взять молоток и забить его. А не искать способы усложнить себе жизнь.
0
Обычно надо кириллицу и ничего лишнего.
Вам — возможно. Но мир слегка больше, чем ареал распространения языков использующих кириллицу.
Зачем разбираться какая либа какие приколы учитывает (полагаю, жабий язык нативно их едва ли умеет...)?
«Жабий язык» их «нативно» учитывает просто в силу того, что изначально (с момента появления языука) весь текст внутри программы хранится и обрабатывается именно как юникод.
Или думать как избавиться от лишнего, если не хочется тащить за программкой/прошивкой мегабайты ненужного кода.
Весь прикол ситуации в том, что «мегабайты ненужного кода» понадобились автору топика из-за того, что они использует 1251. С юникодом этой проблемы бы не существовало вообще, не нужны были бы никакие перекодировки и библиотеки.
Надо понимать, что если нужно забить гвоздь, иногда можно просто взять молоток и забить его.
Я именно это и предложил, вместо изобретения очередных костылей с перекодировкой. Ах да, я забыл, что вы не могли пройти мимо предложения использовать «новомодный» UTF-8.
0
Если использовать всякое бескомпромиссное барахло, учитывающее капризы всего мира — можно опупеть. Так что нафиг этот весь мир…
изначально (с момента появления языука) весь текст внутри программы хранится и обрабатывается именно как юникод
Самый прикол в том, что когда появился жабий язык, под юникодом всё ещё понимали просто нормальную двухбайтную кодировку, но не utf и не всякие извращения с составными символами. Сейчас же в моде utf-8, так что жабий язык со своим двухбайтным чаром считается отсталым. utf-16 появился емнип с шестой версии, но появилась ли поддержка всего того ада из статьи? Я сильно сомневаюсь)
«мегабайты ненужного кода» понадобились автору топика из-за того, что они использует 1251
Нет. Перекодировка понадобилась из-за того, что он связался со всякими новомодными json-ами. В остальном программа использует кодировку 1251. И это правильный подход — если приходится путаться с новомодными «технологиями», нужно минимизировать связанную с ними область.
0
Если использовать всякое бескомпромиссное барахло,
Вот 1251 это и есть «бескомпромиссное барахло».
учитывающее капризы всего мира — можно опупеть. Так что нафиг этот весь мир…
Отлично. Переставайте использовать UTF-8 вообще.
Самый прикол в том, что когда появился жабий язык, под юникодом всё ещё понимали просто нормальную двухбайтную кодировку, но не utf и не всякие извращения с составными символами.
Не порите чушь, ей больно. UTF-8 это транспортная кодировка, а 16/32бита — это внутреннее представление.
utf-16 появился емнип с шестой версии, но появилась ли поддержка всего того ада из статьи?<
С пятой версии.
Я сильно сомневаюсь)
Вы просто не разбираетесь в предмете, отсюда и сомнения. Еще раз: UTF-8/16 это транспортные кодировки. Внутреннее представление это отдельная тема, которая сюда никаким боком. Что бы понять написанное мной вам, вероятно, прийдется, немного погуглить. Возможно это пойдет вам на пользу.
Нет. Перекодировка понадобилась из-за того, что он связался со всякими новомодными json-ами.
Нет, она понадобилась из-за использования 1251, а не из-за JSON.
В остальном программа использует кодировку 1251.
Что, вобщем-то, и породило проблему.
И это правильный подход — если приходится путаться с новомодными «технологиями», нужно минимизировать связанную с ними область.
В данном случае правильным был бы подход сменить кодировку. И не пришлось бы ничего «минимизировать», поскольку и проблемы бы не было. А так из-за псевдо-«минимизации» пришлось городить костыль, да еще и клеить его жевачкой, что бы не развалилось. Я уж не говорю о том, что, вообще говоря, UTF-8 это, в некотором смысле, «нативный» формат для браузера, JS и всего остального, что связано с вебом. Любые виндодрочерские 1251 и прочие извращения это поиск приключений на собственную задницу. Данный топик именно об этом — как самому себе создать проблему и «с честью» ее победить. Учитывая, что вы постоянно пытаетесь выглядеть «борцом за правильный софт», весьма удивительно, что вы отстаиваете кривой костыль, да еще и так ревностно.
0
Линуксойд?
0
Нет.
0
поддержка всего того ада из статьи?
Ну вот, опять. Коллега, а вы саму статью читали?

Статья ведь не о юникоде, а о особенностях Letter case преобразований. Статья о том, что в некоторых языках нет однозначного соответствия между прописными и заглавными буквами и это сильно усложняет преобразование регистров и, как следствие, сравнение строк.

Пример с немецкой ß – это самый известный случай, который вошел во множество учебников (man 3 toupper). Как и пример с греческим символом Σ. Это особенности самого языка (грамматики), а не способа кодирования его алфавита. Эти моменты справедливы как для юникода, так и для восьмибитных cp437 или греческой Windows-1253

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

он связался со всякими новомодными json-ами.

Угу …
we_need_to_go_deeper.jpg
Связался с этими HTTP поверх TCP/IP… А ведь мог просто помигать неонкой, как наши деды делали…
0
Касательно кодировок – вспомнился старый анекдот (Действительно старый, и сугубо фидошный):
Общаются два ФИДОшника:
Старый ФИДОШНИК: Ты так можешь — HHHHHHH
Молодой: еумю!
+1
+1
+1
Ну так в этом вашем юникоте все эти глюки возможны. Так что юзать его не стоит. А немцам лучше пофиксить грамматику.

А ведь мог просто помигать неонкой, как наши деды делали…
А почему бы и нет? Понаставят компьютерных операторских станций, операторы потом жалуются что это как смотреть через игольное ушко. Деды делали отличные пульты, где всё было под рукой.
0
Если использовать всякое бескомпромиссное барахло, учитывающее капризы всего мира — можно опупеть. Так что нафиг этот весь мир…
Регулярно проклинаю программистов с аналогичной позицией за то, что их софт у меня работает через жопу. Хорошо, когда для решения проблем хватает AppLocale, а не виртуалки с японской виндой.
+1
Справедливости ради, описанные в приведенной статье проблемы никак не связаны с юникодом.
Это проблемы приведения к верхнему/нижнему регистру с учетом особенностей языков.
К примеру немецкая Эсцет при переводе в верхний регистр заменятся на 2 символа (SS), не зависимо от того юникод это или восьмибитная cp437
+3
Unicode — в принципе говно. Со всем этим адом связываться только в самом крайнем случае.
В жопу локальные кодировки. Даже пока имеешь дело только с английским и русским регулярно вылазят проблемы от кракозябр до «пошли вы в жопу с русскими путями», как только к веселью подключаются иероглифические языки — все вообще работать перестает и с AV вылетает.
К счастью, уникод пог большей части эти проблемы решает. Вот только не поддерживающих его программ по прежнему дофига и регулярно приходится применять различные костыли, вроде AppLocale.

Ну и да, все описанное по ссылке веселье свойственно и неюникодным кодировкам, просто русские с ним не сталкиваются. Ну так у нас и в юникоде таких приколов нет.
+1
Ну так у нас и в юникоде таких приколов нет.
У нас и в 1251 таких проблем нет. Так что пусть те возятся с юникодами те, кому нужны всякие иероглифы и эсцеты, запись задом наперёд, составные символы etc.
0
Туча кодировок вызывает такую же тучу проблем. Уникод един для всех, к тому же, заставляет всех программистов задумываться о том, что язык бывает не только английский и что работа с текстом сложнее, чем кажется на первый взгляд, что повышает качество программ. Сейчас уже проблема «программа не видит русские пути» встречается среди буржуйского софта (а не секрет, в общем-то, что процентов 90 используемого у нас софта — буржуйский) куда реже. Так что все локальные кодировки должны отмереть как атавизм.
У нас и в 1251 таких проблем нет. Так что пусть те возятся с юникодами те, кому нужны всякие иероглифы и эсцеты, запись задом наперёд, составные символы etc.
Давай еще и программы на русском языке писать, нет же проблем, что понять их текст смогут только русские.
+3
Усложнять работу с текстом из-за чужих капризов и извращений? Нет, спасибо.
У немцев эсцет, который после strupr превращается в SS, а при strlwr — уже в ss. Да пожалуйста, но пусть возятся с этим сами.
Давай еще и программы на русском языке писать
А многие и пишут, кириллицей или транслитом. Особенно в областях, далёких от модного программирования на явах и оопах — скажем, в промавтоматике или бухгалтерском учёте. Зачем мучаться с переводом туда-сюда специфических сущностей, если это только усложняет жизнь?
-1
Ну это уже выбор личный — писать кривой софт, работающий только под одной локалью или же правильный софт, правильно работающий на всех системах.
В атмеле, например, выбрали первый вариант, так что на русской винде их софт работает несколько криво. Традиционный косяк — русские пути не любит.
+3
AS4 — хорошая IDE. Достаточно быстрая, а главное — полноценно интегрированная. На русские пути плевать (хотя, возможно, стоило бы добавить проверку путей при запуске и ругаться если в них есть недопустимые символы).

В основном проблемы с текстом вызваны пустяковыми ошибками типа использования Win-кодировки вместо OEM и наоборот; использования ANSI_CHARSET вместо DEFAULT_CHARSET при выводе текста; C-локаль, выбранная CRT. Всё лечится тривиально и без всяких уникотов (обычно несложно пофиксить прям в исполняемом файле).
0
Недопустимые символы в пути — это "|<>*? (а также \/: где-либо, кроме разделителей). Все. Если программа не может обработать корректный путь — это кривая программа. Хотя я не про AS4, а про симулятор в AS5. Она вообще сырая и кривая, хорошо работают там только GCC, MSVS IS и VAX.
Всё лечится тривиально и без всяких уникотов (обычно несложно пофиксить прям в исполняемом файле).
Фиксить в исполнимом файле — это отвратительные костыли. Правильное решение — юникод.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.