Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Как получить код символа в нужной кодировке? (https://javascript.ru/forum/misc/81953-kak-poluchit-kod-simvola-v-nuzhnojj-kodirovke.html)

repulsor 19.02.2021 16:53

Как получить код символа в нужной кодировке?
 
Здравствуйте.

Нужно нативными средствами (то есть, без костылей) получить код символа в нужной кодировке, например, CP866.

Проблема в том, что в JS есть подходящая функция (TextEncoder), но она, в отличии от своей обратной функции (TextDecoder), не принимает параметр с кодировкой, и такое:
let encoder = new TextEncoder('ibm866');
let uint8Array = encoder.encode('А');
console.log(uint8Array);


Дает не: Uint8Array [ 128 ], а: Uint8Array [ 208, 144 ], так как используется UTF-8.

Можно конечно сделать массив, и оттуда получать эти символы, но по некоторым причинам, это не желательно :(

Если кто-то сможет подсказать, как это можно реализовать, буду очень признателен :)

voraa 19.02.2021 19:33

Никак. Ручками перекодировать. Таблицу делать. Обходя всякие препоны.
https://javascript.ru/forum/ajax/815...rchparams.html

repulsor 19.02.2021 21:51

voraa, я так не играю... :no:

Значит развели over 9000 этих кодовых таблиц, а теперь простым трудягам в ручную писать? :(

У TextDecoder почему-то есть указание кодировки, что им было сложно добавить обратный алгоритм в TextEncoder?

В одной функции у них стандарт UTF-8, в другой UTF-16 (charCodeAt), что дальше? Такими темпами не то, что костыли или велосипеды писать нужно, а уже заводское производство их запускать :)

Aetae 19.02.2021 22:06

Неверно - везде utf8:
alert([
'A'.charCodeAt(0),
'A'.codePointAt(0)
].join('\n'))


А вот на счёт TextEncoder согласен. Изначально в стандарте он как раз поддерживал любую кодировку, но у текущих товарищей у руля стандарта мания принудительного навязывания utf8, потому всё иное выпиливают со страшной силой. Тот же fetch из коробки уже не умеет ничего кроме utf8. Очевидно, что внутри браузера всё нужное для конвертации в любую сторону есть, но из-за такой политики приходится тащить кучу мусорного дублирующего кода.

repulsor 19.02.2021 22:27

Цитата:

Сообщение от Aetae (Сообщение 533913)
Неверно - везде utf8:
alert([
'A'.charCodeAt(0),
'A'.codePointAt(0)
].join('\n'))


Aetae, попробуйте вернуть код русской А, результат 1040, а не 53392 (Hex: D0 90), это UTF-16, насколько я помню, или нет?

Цитата:

Сообщение от Aetae (Сообщение 533913)
А вот на счёт TextEncoder согласен. Изначально в стандарте он как раз поддерживал любую кодировку

Можете подсказать когда убрали? Я вот не нашел версию, чтобы работало с кодировкой :(

Aetae 19.02.2021 22:50

Цитата:

Сообщение от repulsor (Сообщение 533917)
Можете подсказать когда убрали? Я вот не нашел версию, чтобы работало с кодировкой :(

Х.з. мб в nightly каких-то версий фокса было. Я об этих штуках первый раз читал когда они были в статусе предложения и тогда там всё было, а когда спустя n лет оно мне понадобилось - уже ничего не было.

А по поводу charCodeAt - вы правы, а я не прав.

..upd:
Цитата:

Note: Prior to Firefox 48 and Chrome 53, an encoding type label was accepted as a paramer to the TextEncoder object

voraa 19.02.2021 22:56

Цитата:

Сообщение от repulsor
У TextDecoder почему-то есть указание кодировки, что им было сложно добавить обратный алгоритм в TextEncoder?

Разумеется сложно.
TextDecoder переводит из каких то кодировок в Юникод в кодировку UTF16, в которой хранятся строки в javascript.
Теперь представьте, что любую строку из javascript мы захотим преобразовать в CP866, win1251 и проч. Что делать с китайскими иероглифами? С греческими буквами?

repulsor 19.02.2021 23:28

Цитата:

Сообщение от Aetae (Сообщение 533919)
..upd:

Aetae, читал, да. В Chrome правда все равно не получилось, посмотрю еще в более младшей версии.

voraa, ну правильно, я же говорю, давайте будем сами делать костыли-велосипеды... То из 16 в 8, то еще куда-то... Они там сверху не могут порой по n лет что-то исправить (а скорее, не хотят). Зато фреймворки выходят со скоростью света :)

P. S. Не сочтите за личное ;) просто так уже задолбало, то с Canvas, то с формами, то еще с чем-то.

voraa 19.02.2021 23:52

Цитата:

Сообщение от repulsor
То из 16 в 8, то еще куда-то..

Ну с этим то как раз все ясно.
Javascript работает в Юникоде. Есть три основных способа кодирования символов в Юникоде. UTF32- самый универсальный, простой и быстрый. Но жрет много памяти. UTF8 - универсальный, памяти в большинстве случаев занимает меньше, но на компьютере обрабатывается медленнее. Ну и UTF16 - Не достаточно универсален (не все символы можно представить) но вполне удовлетворителен по памяти и времени)
Цитата:

Сообщение от repulsor
Они там сверху не могут порой по n лет что-то исправить (а скорее, не хотят)

Не думаю. Просто нет хорошего, устраивающего всех решения
Ну вот надо строку в win1251 перевести, а в строке иероглиф. Что делать? Выбрасывать исключение? Заменять каким то кодом? (в Win1251 все коды заняты)

repulsor 20.02.2021 00:09

Цитата:

Сообщение от voraa (Сообщение 533922)
Ну вот надо строку в win1251 перевести, а в строке иероглиф. Что делать? Выбрасывать исключение? Заменять каким то кодом? (в Win1251 все коды заняты)

voraa, ну как всегда, пишем параметр options, с флагом по умолчанию ignore, а там уже по желаю: показывать сообщение об ошибке, заменить на указанный символ.

В конце концов, JS один из самых гибких языков.

Сейчас вот даже вопрос с генерацией таблицы в CP866 не так однозначен, нужно подумать, как лучше сделать :(

Aetae 20.02.2021 04:15

Цитата:

Сообщение от voraa (Сообщение 533922)
Не думаю. Просто нет хорошего, устраивающего всех решения

Но есть готовый механизм, продуманный в своё время умными людьми: ставишь для form атрибут accept-charset и браузер спокойно кодирует текст в input'ах из текущей кодировки в указанную, перед тем как послать форму на сервер. (Символы не влезающие в кодировку он кодирует как html entity.)
Это конечно типа legacy, но пока не deprecated.)

Жаль только никакого хитрого метода заюзать это в коде я лично не придумал.

voraa 20.02.2021 11:39

Цитата:

Сообщение от repulsor
Значит развели over 9000 этих кодовых таблиц, а теперь простым трудягам в ручную писать?

Ну не так их уж и много.
Разрешенные в TextDecoder (кроме iso-2022-cn, iso-2022-cn-ext) тут
https://developer.mozilla.org/en-US/..._API/Encodings

Для простых кодировок (которые не китайско-японские и ограничиваются 256 кодами) можно прикрутить что то типа такого
<script>
class TextEncoderExt {
	constructor (utfLabel="utf-8", options={fatal:false}) {
// options.fatal  - true - выбрасывать исключение при ошибках кодирования.
// options.code - числовой код, который подставляется для несуществующих символов.
// если не указан, несуществующий символ пропускается.

		if (utfLabel.toLowerCase().indexOf('utf')>=0) return new TextEncoder('utf-8', options)
		this.codetable = {};
		this.opt = options;
		const arb = new Uint8Array(256)
		for (let i = 0; i<256; i++) arb[i]=i; 
		const codestr = new TextDecoder(utfLabel).decode(arb);
		for (let i=0; i<256; i++) this.codetable[codestr.codePointAt(i)] = i;
	}
	
	encode (str) {
		const l = str.length;
		const buf = new Uint8Array(l);
		let j = 0;
		for (let i = 0; i<l; i++) {
			let v = this.codetable[str.codePointAt(i)];
			if (v === undefined) {
				if (this.opt?.fatal) throw new Error('EncodeExt error');
				if (typeof this.opt?.code == 'number') v=this.opt.code & 255;
			}
			if (v !== undefined) buf[j++] = v;
		}
		return (j<l)? buf.slice(0,j) : buf;
	}
}

const strin1="Это строка на кирилице. В “win-1251” и обратно …"

const buf1 = new TextEncoderExt('CP1251').encode(strin1)
const strout1= new TextDecoder('CP1251').decode(buf1)

console.log (strin1)
console.log (strout1)

const strin2="Это строка на кирилице. В “CP866” и обратно …"

const buf2 = new TextEncoderExt('866', {code:240}).encode(strin2) // Ё вместо несуществующих символов
const strout2= new TextDecoder('866').decode(buf2)

console.log (strin2)
console.log (strout2)

const strin3="Это строка на кирилице. В “utf-8” и обратно …"

const buf3 = new TextEncoderExt('utf-8').encode(strin3)
const strout3= new TextDecoder('utf-8').decode(buf3)

console.log (strin3)
console.log (strout3)
</script>

repulsor 20.02.2021 11:51

voraa,
кстати, правильно ли я понял, что CP437 нужно только в ручную выписывать?

voraa 20.02.2021 12:02

Цитата:

Сообщение от repulsor
CP437 нужно только в ручную выписывать?

Ну да.
Такой TextDecoder('cp437') не знает.
Слетает с ошибкой.

repulsor 20.02.2021 12:47

voraa,
самое интересное, что 437 это альма-матер этих ibm кодировок, и что ее путают с другими, хотя они уже от нее образовались...


Часовой пояс GMT +3, время: 11:39.