FromUtf8 ещё раз

Программы на Clarion, шаблоны, библиотеки и пр.

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Встала задача по парсингу XML и заполнению БД.
Я благодарю Юрия Философова и Олега А. Руденко за их разъяснения по работе
с XML и классами на нашем форуме.
Распутал работу файла cpxml.clw и других xmlclass.inc XMLCONV.CLW ...
Anatoly Medyntsev добросовестно проштудировал expat.
Универсализм - это наше всё на все случаи жизни!

Пришлось делать свой парсер для конкретных БОЛЬШИХ файлов.

Встала задача перекодировки UTF-8 в CP-1251, она же Windows-1251
MS_1251 и CP-1251.
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Я восхищён Робертом Пайком - по его книге и K&R учился Си.
Превращение громоздкого 4-байтового U+cod из таблицы 256х256
в облегченный Utf-8 (почти таблица 16х16) привело
к фактическому стандарту во всех опер системах.

Разобрался с перекодировкой из Utf-8. Мягко говоря - охренел!!!
Utf-8 преобразовать в U+cod, затем в нужную кодовую страницу...
Вызовы из ОС функций, подгрузка-привязка DLL...

Конвертация в 1251 из utf-8

Blength = MultiByteToWideChar (CP_UTF8, 0, address(S), -1, address(Buffer2), 0)
RetCode = MultiByteToWideChar (CP_UTF8, 0, address(S), -1, address(Buffer2), Blength)
RetCode = WideCharToMultiByte (CP_ACP0, 0, address(Buffer2),Blength, address(Buffer1), Slength, 0, 0)

Универсализм - это наше всё на все случаи жизни!
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Пришлось вспоминать перекодировку в DOS системах.
В обычном INI-файле делаются секции для каждой кодировки.
Алгоритм прост.
Делаются 2 строки-массива -код1 и код2.
Ищется байт-символ в одной строке-массиве и по индексу-позиции
берётся байт-символ из той-же позиции строки-массива код2.
Всё. Сколько кодировок - столько строк-массивов символов в файле.
Даже транслит сделан подобно.

Неужели никто не делал? Обратился в Интернет - и сразу нашлась
таблица соответствия кодов Utf_8 с кодами СP-1251, CP-866, КОИ-8...

Посмотрел. посчитал и получил...
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Код: Выделить всё

FromUtf8  PROCEDURE(STRING StrIn)

    DATE
outStr &STRING, AUTO   ! ссылка на выходная строка
inStr  &STRING, AUTO   ! ссылка на входная строка
i      SIGNED,AUTO     ! индекс-позиция входной строки
j      SIGNED(1)       ! индекс-позиция выходной строки
					   ! он же счётчик сконвертированных символов

  CODE
	inStr &= StrIn					! укажем ссылку-реферал на строку UTF-8 откуда
  	outStr &= NEW STRING(SIZE(inStr))    ! конструктор выходной строки
									! или указать ссылку на строку вывода - куда
  LOOP i = 1 TO SIZE(inStr)            ! цикл по входной строке
    IF VAL(inStr[i]) <= 07FH           ! номер символа меньше 127 -Latin
      outStr[j] = inStr[i]             ! без конвертации в позицию новой строки
    end	
    IF VAL(inStr[i]) = 194           ! номер след. символа 1251
      i += 1        ! след символ
	  outStr[j] = inStr[i]
    end	
    IF VAL(inStr[i]) = 208			! русские символы из 2-х байт
      i += 1        ! след символ
	  IF VAL(inStr[i]) = 129		! буква Ё
		outStr[j] = CHR(VAL(inStr[i]) + 39)
	  else
		IF VAL(inStr[i]) >143
		  outStr[j] = CHR(VAL(inStr[i]) + 48)
		end
      END 
    END
    IF VAL(inStr[i]) = 209			! русские символы
      i += 1        ! след символ
	  IF VAL(inStr[i]) = 145		! буква ё
		outStr[j] = CHR(VAL(inStr[i]) + 39)
	  else
		IF VAL(inStr[i]) < 144
		 outStr[j] = CHR(VAL(inStr[i]) + 112)
		end
      END	
    END
		! здесь проверка символов кириллицы - не русских букв
    j += 1      ! счётчик сконвертированных символов
  END
! вариант возврата результата
  V = CLIP (outStr)     ! пробелы в конце убираем
  DISPOSE (outStr)      ! Освободить память в куче
  RETURN V              ! вернём строку
Нужны некоторые проверки на границы допустимых символов,
но это работает - проверенно.

и никаких обёрток!!!...
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Вот таблица
1251.ods
1251.zip
(39.91 КБ) 45 скачиваний
Clarion v.6-11 и т.п. Код-всё, данные-частности
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7322
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

FromUtf8 ещё раз

Сообщение Игорь Столяров »

Здравствуйте ! :)

А зачем вот это всё ? ;)
Более 20 лет конвертация кодировок делается через WinAPI ... есть разные реализации, например:

Код: Выделить всё

! Перекодировка строки текста UTF8 -> ANSI
UTF8toANSI       Procedure(String sStr)  !,String
UnicodeText   String(Size(sStr)*2+2)
ANSIText      String(Size(sStr)*2+2)
bytesWritten  Long, Auto
Len           Long, Auto
  Code
  If (Size(sStr) = 0) Or (sStr = '<0>') then Return ''
  else
     bytesWritten = MultiByteToWideChar(65001,        0,Address(sStr),     Len(sStr),  Address(UnicodeText),Size(UnicodeText))
     Len          = WideCharToMultiByte(GetACP(),0,Address(UnicodeText),bytesWritten,Address(ANSIText),   Size(ANSIText),0,0)
     If Len <= 0 then Return ''
     else
        Loop
          If Sub(ANSIText,Len,1) = '<0>' then Len -= 1 else Break.
        end
        Return Sub(ANSIText,1,Len)
     end
  end
За теми кто отстал - не возвращаться. (С) Кодекс
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Просто ещё один частный вариант для частных случаев...
Clarion v.6-11 и т.п. Код-всё, данные-частности
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7322
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

FromUtf8 ещё раз

Сообщение Игорь Столяров »

Bukreev писал(а): 06 Февраль 2023, 20:25 один частный вариант
А Вы уверены что Ваша "табличка из интернета" сработает на всём многообразии версий Windows от 95 до 11 ?
Вы тестировали такое решение на всех вариантах кодовых страниц Windows и национальных кодировок ?
За теми кто отстал - не возвращаться. (С) Кодекс
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Делалось только для 1251
Другие кодовые страницы и кодировки даже не рассматривались.
Частный вариант для частного применения.
Clarion v.6-11 и т.п. Код-всё, данные-частности
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3131
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

FromUtf8 ещё раз

Сообщение Дед Пахом »

Не удивлюсь если MultiByteToWideChar/WideCharToMultiByte так и работают с таблицами.
С уважением, ДП
Аватара пользователя
RaFaeL
✯ Ветеран ✯
Сообщения: 1376
Зарегистрирован: 24 Март 2009, 17:59
Откуда: НН
Благодарил (а): 7 раз
Поблагодарили: 1 раз
Контактная информация:

FromUtf8 ещё раз

Сообщение RaFaeL »

А символы все охватываете? Например символ "№" который в UTF8 трехбайтовый
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

1251.ods
(43.57 КБ) 42 скачивания
Чуть обновил файл таблицы для знаков.
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Добавил проверку 3- байтовых

Код: Выделить всё

FromUtf8  PROCEDURE(STRING StrIn)

    DATE
outStr &STRING, AUTO   	! ссылка на выходная строка
inStr  &STRING, AUTO   	! ссылка на входная строка
i      SIGNED, AUTO    	! индекс-позиция входной строки  =0
j      SIGNED, AUTO    	! индекс-позиция выходной строки =0
					   	! он же счётчик сконвертированных символов
in3b	STRING		   	! для 3-х байтовых символов Utf-8 последний байт
out3b	STRING			! символы 1251 соответственно

  CODE
	inStr  &= StrIn					! укажем ссылку-реферал на строку UTF-8 откуда
  	outStr &= NEW STRING(SIZE(inStr))    ! конструктор выходной строки
									! или указать ссылку на строку вывода - куда
	! пара массивов для 3-х байтовых символов Utf-8 последний байт
	in3b = '<147><147><152><153><154><156><157><158><160><161><162><166><176><185><186><172><150>'
	out3b= '<150><151><145><146><130><147><148><132><134><135><149><133><137><139><155><136><185>'

  LOOP i = 1 TO SIZE(inStr)            ! цикл по входной строке
    j += 1      ! счётчик сконвертированных символов
    IF VAL(inStr[i]) <= 07FH           ! номер символа меньше 127 -Latin
      outStr[j] = inStr[i]             ! без конвертации в позицию новой строки
    end	
    IF VAL(inStr[i]) = 194           ! номер след. символа 1251
      i += 1        ! след символ
	  outStr[j] = inStr[i]
    end	
    IF VAL(inStr[i]) = 208			! русские символы из 2-х байт
      i += 1        ! след символ
	  IF VAL(inStr[i]) = 129		! буква Ё
		outStr[j] = CHR(VAL(inStr[i]) + 39)
	  else
		IF VAL(inStr[i]) >143
		  outStr[j] = CHR(VAL(inStr[i]) + 48)
		end
      END 
    END
    IF VAL(inStr[i]) = 209			! русские символы
      i += 1        ! след символ
	  IF VAL(inStr[i]) = 145		! буква ё
		outStr[j] = CHR(VAL(inStr[i]) + 39)
	  else
		IF VAL(inStr[i]) < 144
		 outStr[j] = CHR(VAL(inStr[i]) + 112)
		end
      END	
    END								! русские символы 209
	! здесь проверка символов кириллицы - не русских 15 штук 2-байтовые 209,210>143
	! ищем знаки 3-байтовые, типа номер №, многоточие... евро
	IF VAL(inStr[i]) = 226			! 3-байтовые 226 - достаточно для проверки
      i += 1        ! след символ
	  IF  VAL(inStr[i]) = 132			! 3-байтовые 132
	    i += 1        ! след символ
	    IF  VAL(inStr[i]) = 162			! дублирован 162, поэтому отдельно		
		  outStr[j] = '<153>'			! товарныйзнак 
		  cycle					! нашли - в начало цикла
		end
	  end							! 3-байтовые 132
      i += 1        				! след байт перескакиваем на символ
	  LOOP s# = 1 TO 17				! SIZE(in3b)
		  IF  VAL(in3b[s#]) = VAL(inStr[i])			! 3-байтовые 128,130,132
			outStr[j] = out3b[s#]
			break								! нашли-искать не надо
		  end
	  end		! LOOP s# = 1 TO SIZE(in3b)

	end		! IF VAL(inStr[i]) = 226

  END	!  LOOP i = 1 TO SIZE(inStr)
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

STRING(17) для строк пар кодов , чтобы компилятор не ругался
На тесте № нашёл.
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Добавил НЕ русские символы
Уменьшил время возвратом в начало цикла, когда нашли.
Полная перекодировка CP-1251
Clarion v.6-11 и т.п. Код-всё, данные-частности
Ответить