FromUtf8 ещё раз

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

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

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

FromUtf8 ещё раз

Сообщение Bukreev »

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

FromUtf8  PROCEDURE(STRING StrIn)

    DATE
outStr &STRING, AUTO   	! ссылка на выходная строка
inStr  &STRING, AUTO   	! ссылка на входная строка
i      SIGNED, AUTO    	! индекс-позиция входной строки  =0
j      SIGNED, AUTO    	! индекс-позиция выходной строки =0
					   	! он же счётчик сконвертированных символов
in3b	STRING(17)	   	! для 3-х байтовых символов Utf-8 последний байт
out3b	STRING(17)		! символы 1251 соответственно
in2b	STRING(13)	   	! для 2-х байтовых символов Utf-8 последний байт
out2b	STRING(13)		! символы 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>'

	in2b = '<146><147><148><149><150><151><152><153><154><155><156><158><159>'
	out2b= '<144><131><186><190><179><191><188><154><156><158><157><162><159>'

  LOOP i = 1 TO SIZE(inStr)            ! цикл по входной строке
    j += 1      ! счётчик сконвертированных символов
    IF VAL(inStr[i]) <= 07FH           ! номер символа меньше 127 -Latin
      outStr[j] = inStr[i]             ! без конвертации в позицию новой строки
	  cycle					! нашли - в начало цикла
    end	
    IF VAL(inStr[i]) = 194           ! номер след. символа 1251
      i += 1        ! след символ
	  outStr[j] = inStr[i]
	  cycle					! нашли - в начало цикла
    end	
    IF VAL(inStr[i]) = 208			! русские символы из 2-х байт
      i += 1        ! след символ
	  IF VAL(inStr[i]) = 129		! буква Ё
		outStr[j] = CHR(VAL(inStr[i]) + 39)
	    cycle					! нашли - в начало цикла
	  else
		IF VAL(inStr[i]) >143
		  outStr[j] = CHR(VAL(inStr[i]) + 48)
	      cycle					! нашли - в начало цикла
		end
      END 
    END
    IF VAL(inStr[i]) = 209			! русские символы
      i += 1        ! след символ
	  IF VAL(inStr[i]) = 145		! буква ё
		outStr[j] = CHR(VAL(inStr[i]) + 39)
	    cycle					! нашли - в начало цикла
	  else
		IF VAL(inStr[i]) < 144
		 outStr[j] = CHR(VAL(inStr[i]) + 112)
  	    cycle					! нашли - в начало цикла
		end
      END	
    END								! русские символы 209
	! здесь проверка символов кириллицы - не русских 15 штук 2-байтовые 209,210>143
    IF VAL(inStr[i]) = 209			! НЕрусские символы 209
      i += 1        ! след символ
	  LOOP s# = 1 TO 13				! SIZE(in2b)
		  IF  VAL(in3b[s#]) = VAL(inStr[i])			! 2-байтовые
			outStr[j] = out3b[s#]
			break								! нашли-искать не надо
		  end
	  end		! LOOP s# = 1 TO SIZE(in2b)
    END								! НЕрусские символы 209
    IF VAL(inStr[i]) = 210			! НЕрусские символы 210
      i += 1        ! след символ
	  IF VAL(inStr[i]) = 145		! 
		outStr[j] = 180
 	    cycle					! нашли - в начало цикла
	  end
	  IF VAL(inStr[i]) = 144		! 
		outStr[j] = 165
 	    cycle					! нашли - в начало цикла
	  end
    END								! НЕрусские символы 210
	! ищем знаки 3-байтовые, типа номер №, многоточие... евро
	IF VAL(inStr[i]) = 226			! 3-байтовые 226 - достаточно для проверки
      IF  VAL(inStr[i+1]) = 132			! 3-байтовые 132
	    IF  VAL(inStr[i+2]) = 162		! дублирован 162, поэтому отдельно		
		  outStr[j] = '<153>'			! товарныйзнак 
          i += 2        				! след байт перескакиваем на символ
		  cycle					! нашли - в начало цикла
		end
	  end							! 3-байтовые 132
      i += 2        				! след байт перескакиваем на символ
	  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)
! вариант возврата результата
  V = CLIP (outStr)     ! пробелы в конце убираем
  DISPOSE (outStr)      ! Освободить память в куче
  RETURN V              ! вернём строку
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

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

FromUtf8 ещё раз

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

Bukreev писал(а): 07 Февраль 2023, 20:15 Добавил проверку 3- байтовых

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

FromUtf8  PROCEDURE(STRING StrIn)
<skipped>
То, что этот код не компилируется - не беда. Беда в том, что после устранения косяков программа падает с ошибкой Index out of range.
С уважением, ДП
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Ранее писал - это варианты...
Bukreev писал(а): 06 Февраль 2023, 20:13 Нужны некоторые проверки на границы
Здесь также проверка на пустую строку
Игорь Столяров писал(а): 06 Февраль 2023, 20:20 If (Size(sStr) = 0) Or (sStr = '<0>') then Return ''
Т.е. проверки ДО вызова процедуры
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

МОЙ вариант процедуры

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

                     MEMBER('gar.clw')                     ! Это MEMBER module

FromUtf8             PROCEDURE (STRING StrIn, STRING StrOut) ! Объявление Процедуры/Функции (не прототипа)

!====================================================
! Перед точкой Врезки: %DataSection) DESC(Data Section) ARG()
outStr &STRING, AUTO       ! ссылка на выходная строка
inStr  &STRING, AUTO       ! ссылка на входная строка
!inStrLng    Long        ! длина входной строки - ускорить-без SIZE(inStr) RTL
i      SIGNED, AUTO        ! индекс-позиция входной строки  =0
j      SIGNED, AUTO        ! индекс-позиция выходной строки =0
                           ! он же счётчик сконвертированных символов
!in3b    STRING(17)           ! для 3-х байтовых символов Utf-8 последний байт
!out3b    STRING(17)        ! символы 1251 соответственно
!in2b    STRING(13)           ! для 2-х байтовых символов Utf-8 последний байт
!out2b    STRING(13)        ! символы 1251 соответственно
                        ! инициализация в обьявлении строковой константы
                        ! должна определить СТАТИЧЕСКУЮ память -ускорить работу
in3b     STRING('<147><147><152><153><154><156><157><158><160><161><162><166><176><185><186><172><150>')
out3b    STRING('<150><151><145><146><130><147><148><132><134><135><149><133><137><139><155><136><185>')

in2b     STRING('<146><147><148><149><150><151><152><153><154><155><156><158><159>')
out2b    STRING('<144><131><186><190><179><191><188><154><156><158><157><162><159>')
! После точки Врезки: %DataSection) DESC(Data Section) ARG()
!===========================================================================
  CODE                                                     ! Начало кода обработки

! Перед точкой Врезки: %ProcessedCode) DESC(Код обработки) ARG()
 ! строки параметры по адресу+длина
    inStr  &= StrIn        ! укажем ссылку-реферал на строку UTF-8 откуда
    outStr &= StrOut       ! указать ссылку на строку вывода - куда
    !Stop(StrIn)
    !Stop(SIZE(StrIn))
    !Stop(StrOut)
    !Stop(SIZE(StrOut))
    outStr &= NEW STRING(SIZE(inStr))    ! конструктор выходной строки
    !Stop(SIZE(outStr))

    ! пара массивов для 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>'

    !in2b = '<146><147><148><149><150><151><152><153><154><155><156><158><159>'
    !out2b= '<144><131><186><190><179><191><188><154><156><158><157><162><159>'
  j = 0
  LOOP i = 1 TO SIZE(StrIn)            ! цикл по входной строке
    j += 1      ! счётчик сконвертированных символов
    IF VAL(StrIn[i]) <= 07FH           ! номер символа меньше 127 -Latin
      !Stop(StrIn[i] &'  i=' &i)
      outStr[j] = StrIn[i]             ! без конвертации в позицию новой строки
      !Stop(outStr[j] &'  j=' &j)
      cycle                    ! нашли - в начало цикла
    end    
    IF VAL(StrIn[i]) = 194           ! номер след. символа 1251
      i += 1        ! след символ
      outStr[j] = StrIn[i]
      !Stop(outStr[j] &'  194j=' &j)
      cycle                    ! нашли - в начало цикла
    end    
    IF VAL(StrIn[i]) = 208            ! русские символы из 2-х байт
      i += 1        ! след символ
      IF VAL(StrIn[i]) = 129        ! буква Ё
        outStr[j] = CHR(VAL(StrIn[i]) + 39)
        !Stop(outStr[j] &'  208j=' &j)
        cycle                    ! нашли - в начало цикла
      else
        IF VAL(StrIn[i]) >143
          outStr[j] = CHR(VAL(StrIn[i]) + 48)
          !Stop(outStr[j] &'  143j=' &j)
          cycle                    ! нашли - в начало цикла
        end
      END 
    END
    IF VAL(StrIn[i]) = 209            ! русские символы
      i += 1        ! след символ
      IF VAL(StrIn[i]) = 145        ! буква ё
        outStr[j] = CHR(VAL(StrIn[i]) + 39)
        !Stop(outStr[j] &'  209j=' &j)
        cycle                    ! нашли - в начало цикла
      else
        IF VAL(StrIn[i]) < 144
         outStr[j] = CHR(VAL(StrIn[i]) + 112)
         !Stop(outStr[j] &'  <144j=' &j)
          cycle                    ! нашли - в начало цикла
        end
      END    
    END                                ! русские символы 209
    ! здесь проверка символов кириллицы - не русских 15 штук 2-байтовые 209,210>143
    IF VAL(StrIn[i]) = 209            ! НЕрусские символы 209
      i += 1        ! след символ
      LOOP s# = 1 TO 13                ! SIZE(in2b)
          IF  VAL(in3b[s#]) = VAL(StrIn[i])            ! 2-байтовые
            outStr[j] = out3b[s#]
            !Stop(outStr[j] &'  209j=' &j)
            break                                ! нашли-искать не надо
          end
      end        ! LOOP s# = 1 TO SIZE(in2b)
    END                                ! НЕрусские символы 209
    IF VAL(StrIn[i]) = 210            ! НЕрусские символы 210
      i += 1        ! след символ
      IF VAL(StrIn[i]) = 145        ! 
        outStr[j] = 180
        !Stop(outStr[j] &'  210j=' &j)
         cycle                    ! нашли - в начало цикла
      end
      IF VAL(StrIn[i]) = 144        ! 
        outStr[j] = 165
        !Stop(outStr[j] &'  210j=' &j)
         cycle                    ! нашли - в начало цикла
      end
    END                                ! НЕрусские символы 210
    ! ищем знаки 3-байтовые, типа номер №, многоточие... евро
    IF VAL(StrIn[i]) = 226            ! 3-байтовые 226 - достаточно для проверки
      IF  VAL(StrIn[i+1]) = 132            ! 3-байтовые 132
        IF  VAL(StrIn[i+2]) = 162        ! дублирован 162, поэтому отдельно        
          outStr[j] = '<153>'            ! товарныйзнак
          !Stop(outStr[j] &'  226j=' &j)
          i += 2                        ! след байт перескакиваем на символ
          cycle                    ! нашли - в начало цикла
        end
      end                            ! 3-байтовые 132
      i += 2                        ! след байт перескакиваем на символ
      LOOP s# = 1 TO 17                ! SIZE(in3b)
          IF  VAL(in3b[s#]) = VAL(StrIn[i])            ! 3-байтовые 128,130,132
            outStr[j] = out3b[s#]
            !Stop(outStr[j] &'  226j=' &j)
            break                                ! нашли-искать не надо
          end
      end        ! LOOP s# = 1 TO SIZE(in3b)
    end        ! IF VAL(StrIn[i]) = 226

  END    !  LOOP i = 1 TO SIZE(StrIn)
  !Stop('Utf8 ' &outStr)
  Qt:ValueA = outStr
! вариант возврата результата
! После точки Врезки: %ProcessedCode) DESC(Код обработки) ARG()
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

Процедура не возвращает значения как обычно.
Отказался от процедуры - сделал "рутинку" подпрограмму
Ведь даже доли процента при больших файлах - это время...
Отсюда варианты - ищу самый быстрый вариант.

Выход из ранга должен пропасть для этого варианта
Bukreev писал(а): 13 Февраль 2023, 22:38 outStr &= NEW STRING(SIZE(inStr)) ! конструктор выходной строки
Clarion v.6-11 и т.п. Код-всё, данные-частности
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3131
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

FromUtf8 ещё раз

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

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

FromUtf8 ещё раз

Сообщение Bukreev »

Спасибо за подсказку xFiles
Нашёл, установил, посмотрел...

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

  ! ------ Start utf-8 Decoding --------
  utf8UseUString = false
  if self._LoadEncodingIsUTF8 and self.DontUTF8Decode = 0
    if self.NoUTF8Before = 1
      ! Check for a double byte UTF-8 character
      if OkayToCopy                              ! Normal Copy
        loop utf8X = DataStartPos to DataEndPos
          if self.BinData[utf8X] >= '<192>'
            self.NoUTF8Before = false                 ! utf-8 found
            break
          end
        end
      else                                       ! Use Decoded copy
        loop utf8X = DataStartPos to (cx-1)
          if self.BinData[utf8X] >= '<192>'
            self.NoUTF8Before = false                 ! utf-8 found
            break
          end
        end
        if self.NoUTF8Before = 1
          loop utf8X = 1 to cs
            if t[utf8X] >= '<192>'
              self.NoUTF8Before = false               ! utf-8 found
              break
            end
          end
        end
      end
    end
    if self.NoUTF8Before = 0                          ! i.e. utf-8 found before
      ! Copy data to u and then utf-8 decode this string
      Do CopyDataToU
      ! ------ Start UTF-8 Decode --------
      ! TODO: use the MultiByteToWideChar/WideCharToMultiByte APIs to correctly handle all Unicode text, code pages
      ! and conversion to an from ANSI. The _NetUnicode class would be ideal for this
      ! see http://www1.tip.nl/~t876506/utf8tbl.html
      loop utf8x = 1 to utf8size
        case Val(u[utf8x])      ! May08: Changed this to use val and do integer comparisons, which fixed a decoding bug
        ! ----------------
        of 192 to 223                ! 2 byte utf-8, May08: Changed to using integers and Val() rather than a string comparison.
        ! ----------------
          if utf8x < utf8size
            utf8UseUString = true
            u[utf8x] = chr(bshift(val(u[utf8x])-192,6) + (val(u[utf8x+1])-128))
            if utf8x+1 < utf8size
              u[utf8x+1 : utf8size-1] = u[utf8x+2 : utf8size]
            end
            utf8size -= 1
          end
        ! ----------------
        !of 224 to 239                   ! 3 byte utf-8 - not implemented
        ! ----------------
        ! ----------------
        !of 240 to 247                   ! 4 byte utf-8 - not implemented
        ! ----------------
        ! ----------------
        !of 248 to 251                   ! 5 byte utf-8 - not implemented
        ! ----------------
        ! ----------------
        !of 252 to 253                   ! 6 byte utf-8 - not implemented
        ! ----------------
        ! ----------------
        !of 254 to 255                   ! illegal utf-8 code
        ! ----------------
        end                                      ! end of case
      end
      ! ------ End UTF-8 Decode --------
    end

  end
  ! ------ Finish utf-8 Decoding --------
  !self.log('AssignField','xxx  Finish utf-8 Decoding ')
Так понял битовые операторы как бы лучше присваивания
Clarion v.6-11 и т.п. Код-всё, данные-частности
Bukreev
Посетитель
Сообщения: 36
Зарегистрирован: 05 Февраль 2006, 17:49
Откуда: Orenburg
Контактная информация:

FromUtf8 ещё раз

Сообщение Bukreev »

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

FromUtf8 ещё раз

Сообщение Bukreev »

Спешка утихла - сделал тестовую прогу, как положено.
Выложил в _Unsorted FromUtf8.7z. Результат в файле
Rez001.txt
(2.7 КБ) 48 скачиваний
2 первые строки:
00000001 0.00000000 [1828] Utf8 вызываем процедуру конвертирования Utf8-1251
00000002 0.00004710 [1828] Utf8 закончили процедуру конвертирования Utf8-1251
Дед Пахом теперь может сравнить скорость обработки.
Добавил ПОЛНУЮ обработку CP-1251. Выловил ошибки, надеюсь все.
Clarion v.6-11 и т.п. Код-всё, данные-частности
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3131
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

FromUtf8 ещё раз

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

У меня иссяк запал :P
С уважением, ДП
Ответить