Имя: Пароль:
1C
1C 7.7
v7: Слишком долго происходит преобразование строки в UTF8
0 zenon46
 
02.03.22
19:01
Доброго дня!
Понадобилось из 7.7 сделать выгрузку на сайт на битриксе, разрабы запросили в формате json, сделать сделал, но преобразование в строку в формате UTF8 занимает слишком много времени.
Вот по такому алгоритму, строка длиной 6.5млн символов, обрабатывается минут 40, что очень долго (

    Длина=СтрДлина(Стр);
    Итог="";
    Для Н=1 По Длина Цикл
        Знак=Сред(Стр,Н,1);
        Код=КодСимв(Знак);
        Если Код<128 Тогда
            Итог=Итог+Знак;
        Иначе
            Если (Код>=КодСимв("А"))И(Код<=КодСимв("п")) Тогда
                Итог=Итог+Симв(208)+Симв(144+Код-КодСимв("А"));
            ИначеЕсли (Код>=КодСимв("р"))И(Код<=КодСимв("я")) Тогда
                Итог=Итог+Симв(209)+Симв(128+Код-КодСимв("р"));
            ИначеЕсли (Знак="ё") Тогда
                Итог=Итог+Симв(209)+Симв(145);
            ИначеЕсли (Знак="Ё") Тогда
                Итог=Итог+Симв(208)+Симв(129);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
1 Garikk
 
02.03.22
19:13
вот даже если не вникать в то что это 7.7, надо выкинуть все КодСимв для константных значений, это уже ускорит работу, также Симв(код) - с фиксированными кодами также переделать на константы
это просто с точки зрения программинга улучшит производительность
2 NorthWind
 
02.03.22
19:39
(0) Наскок я помню, через ADO Stream можно было забубенить и быстро работает.
Вот пример гуглится https://forum.script-coding.com/viewtopic.php?id=997
3 NorthWind
 
02.03.22
19:42
(1) на скрипте 6 лямов символов строки даже если просто выбирать в переменную по одному и больше ничего не делать - уже, по-моему, долго выйдет. На машинном коде должна быть такая операция.
4 acanta
 
02.03.22
20:00
А Стрзаменить это цикл в цикле?
5 АгентБезопасной Нацио
 
02.03.22
20:06
6 NorthWind
 
02.03.22
20:09
(4) нужно смотреть реализацию. Но замена тормозная сама по себе еще и потому, что новая строка может быть длиннее прежней, соответственно, нужно выделять кучу под новую строку и, если не повезет, то много раз.
7 NorthWind
 
02.03.22
20:12
(5) "теперь мы временно без", как пел БГ. Архив временно отключён :)
8 АгентБезопасной Нацио
 
02.03.22
20:15
(7) А как я туда попал?
впрочем, я ТС'у уже скинул код оттуда
9 Злопчинский
 
02.03.22
21:15
//********************************************************************************************************************************
// http://www.skalnyy.com/1s-perekodirovka-fajla/
// ВОЗМОЖНЫЕ ВАРИАНТЫ КОДИРОВОК "UTF-8" "KOI8-R" "Windows-1251" "ISO-8859-5"

Процедура глИзменитьКодовуюСтраницуФайла(имяФайла, исходнКодировка, нужнаяКодировка) Экспорт
    Если ФС.СуществуетФайл(имяФайла) = 0 Тогда
        Сообщить("Файл " + имяФайла + " - не найден! Изменение кодировки отменено.", "!");
        Возврат;
    КонецЕсли;
    ScrptCtrl = СоздатьОбъект("MSScriptControl.ScriptControl");
    ScrptCtrl.Language = "VBScript";
    ScrptCtrl.AddCode("
        |Function StrConv(Text,SourceCharset,DestCharset)
        |    Set Stream=CreateObject(""ADODB.Stream"")
        |    Stream.Type=2
        |    Stream.Mode=3
        |    Stream.Open
        |    Stream.Charset=DestCharset
        |    Stream.WriteText Text
        |    Stream.Position=0
        |    Stream.Charset=SourceCharset
        |    StrConv=Stream.ReadText
        |End Function
        |
        |sub ConvertCodepage( fileName, SourceCharset, DestCharset )
        |    set fs = CreateObject(""Scripting.FilesystemObject"")
        |    originalText = fs.openTextFile(fileName,1).readAll()
        |    convertedText = strConv(originalText, SourceCharset, DestCharset )
        |    fs.openTextFile(fileName,2,true).write(convertedText)
        |end sub
        |
        |");
    Module        = ScrptCtrl.Modules("Global");
    CodeObject    = Module.CodeObject;
    CodeObject.ConvertCodepage(имяФайла, исходнКодировка, нужнаяКодировка);
КонецПроцедуры //ИзменитьКодовуюСтраницуФайла()
10 Garikk
 
02.03.22
22:13
прям кровь из глаз...писать конвертор стрингов через промежуточный файл прям девяностыми повеяло и костылями

а вот так если сделать не лучше?
http://www.moretechtips.net/2008/10/convert-string-to-bytes-and-vice-versa.html
11 Злопчинский
 
02.03.22
22:16
(10) я хз что там у ТС, может ему этот конвертор 100 раз в секунду надо по каналу отдавать данные и не успевает...
12 Злопчинский
 
02.03.22
22:17
ждем рабочий код для выполнения в 77 из (10) типа как в (9) ;-)
13 Garikk
 
02.03.22
22:18
(12) ну его достаточно скопипастить в (9)
p.s. мне прям щас проверить негде, если завтра тема не помрет то почекаю
14 Злопчинский
 
02.03.22
22:34
(13) ок, ждемс
15 PloAl
 
02.03.22
23:09
Имхо функции конвертирования не помогут, т.к. насколько помню 7.7 код похож на вставку символов кириллицы utf8 в виде "\u1035" и.т.д.
Код какой то малопонятный, помню сам писал функцию перевода из win1251 в utf8, там все просто получилось сдвиг вроде был 848.

Имхо проблема в (0) это конкатенация большой строки, и писать надо в файл не помню насколько это удобно в 7.7 получиться возможно лишних переносов строк будет много.
16 Смотрящий
 
03.03.22
00:09
ТЗЗамены = СозадтьОбъект("ТаблицаЗначений);
ТЗЗамены.НоваяКолонка("Символ", "Строка", 1);
ТЗЗамены.НоваяКолонка("ЗаменитьНа", "Строка");

ТЗЗамены.НоваяСтрока(); ТЗЗамены.Символ = "А"; ТЗЗамены.ЗаменитьНа = Симв(208) + Симв(144 + КодСимв("А") - КодСимв("А"));
ТЗЗамены.НоваяСтрока(); ТЗЗамены.Символ = "Б"; ТЗЗамены.ЗаменитьНа = Симв(208) + Симв(144 + КодСимв("Б") - КодСимв("А"));
....
ТЗЗамены.НоваяСтрока(); ТЗЗамены.Символ = "р"; ТЗЗамены.ЗаменитьНа = Симв(208) + Симв(128 + КодСимв("р") - КодСимв("р"));
ТЗЗамены.НоваяСтрока(); ТЗЗамены.Символ = "с"; ТЗЗамены.ЗаменитьНа = Симв(208) + Симв(128 + КодСимв("с") - КодСимв("р"));
...
ТЗЗамены.НоваяСтрока(); ТЗЗамены.Символ = "ё"; ТЗЗамены.ЗаменитьНа = Симв(209) + Симв(145);
ТЗЗамены.НоваяСтрока(); ТЗЗамены.Символ = "Ё"; ТЗЗамены.ЗаменитьНа = Симв(208) + Симв(129);

ТЗЗамены.ВыбратьСтроки();
Пока ТЗЗамены.ПолучитьСтроку() = 1 Цикл
Стр = СтрЗаменить(Стр, ТЗЗамены.Символ, ТЗЗамены.ЗаменитьНа);
УонецЦикла;

ЗЫ. Движок 7.7 может рухнуть на какой либо итерации - не сожрет преобразование строки 6.2 мега 128 раз подряд
Приходи - нарежем строку по килобайту, например
17 Chai Nic
 
03.03.22
06:47
А не проще создать файл в нативной 1251 кодировке, а потом на него натравить экзешник перекодировщика?
18 Kigo_Kigo
 
03.03.22
08:43
(17) Я так и делал, только вот екзешник перекодировщика не помню какой был, Нотепад++ что ле
19 ДедМорроз
 
03.03.22
08:46
А на си написать?
Там самое главное,память правильно использовать,чтобы не было операций копирования.
В остальном,запись двух байт вместо одного в память-это очень быстро.
20 1snik_d
 
03.03.22
08:51
Я когда-то делал через ADODB.Stream, работало очень шустро и там необязательно использовать промежуточные файлы, можно прям в памяти фигачить
21 1snik_d
 
03.03.22
08:52
Чисто на 1С делать конвертер - это задница, медленно очень работает.
22 NorthWind
 
03.03.22
09:00
(20) стримы в памяти точно есть, но у меня нет уверенности, что существует "мостик" между семерочными строками и указателем, откуда стриму забирать-отдавать данные. Скорее всего файл будет нужен именно на этом этапе.
23 1snik_d
 
03.03.22
09:06
(22) Делал через MSScriptControl.ScriptControl, передавая туда строку из переменной 1С. Насколько помню там была единственная проблема с длинными строками
24 1snik_d
 
03.03.22
09:07
(23) Их приходилось дробить на части и кусками конвертировать
25 NorthWind
 
03.03.22
09:20
(24) ну уже хлеб...
26 NorthWind
 
03.03.22
09:21
(21) это неудивительно, скриптом посимвольно такие строки никто не дербанит, это несерьезно
27 1snik_d
 
03.03.22
09:47
(25) Даже многомегабайтные ответы от сервера обрабатывались очень шустро, сначала конвертация, потом разбор XML и все через MSScriptControl.ScriptControl с javascript функциями и ADO Stream
28 ДедМорроз
 
03.03.22
10:25
В 1с 7.7 строки однобайтовые и в кодировке windows-1251.
При передаче этой строки в любой com-объект,строка преобразуется в двухбайтовую - для этого выделяется блок памяти и делается преобразование - так как оно на машинном уровне,то мы его почти не замечаем,но доя больших строк будет критично.
При записи в файл никаких преобразований нет,но есть проблемы с символом с кодом 0.
Но,при чтении файла,например,через Scripting FileSystemObject происходит такое же преобразование,но при чтении каждой строки.
Adodb.stream читает файл в память в буфер,используя функции чтения файла и информацию о кодировке.
При преобразовании кодировок он самый быстрый,но подъем всего файла в память - часто очень критично.
29 ДедМорроз
 
03.03.22
10:32
На Си из win-1251 в utf достаточно просто.
Первый проход,считаем сколько байт на каждый символ,там,насколько я помню,символ номера - тир байта,остальные со старшим битом-два.
Получаем размер будущей строки-выделяем память и вперед перекодировать по таблице.
30 zenon46
 
03.03.22
10:37
В памяти не получилось, предприятие просто закрывалось, пришлось делать через файл. Работает быстро.

    Байт=255;
    СтримВход=СоздатьОбъект("ADODB.Stream");
    СтримВход.Type=2;
    СтримВход.charset="windows-1251";
    СтримВход.Open();
    СтримВход.LoadFromFile(Путь+Имя);
    СтримВыход=СоздатьОбъект("ADODB.Stream");
    СтримВыход.Type=2;
    СтримВыход.charset="utf-8";
    СтримВыход.LineSeparator=-1;
    СтримВыход.Open();
    Всего=СтримВход.size;
    Пока СтримВход.EOS=0 Цикл
        СтримВыход.WriteText(СтримВход.ReadText(Байт),?(Байт=-2,1,0));
        Состояние("" + Формат(100 * СтримВход.position/Всего,"Ч(0)5.2")+"%");
    КонецЦикла;
    СтримВыход.SaveToFile(Путь+Имя,2);
31 ДедМорроз
 
03.03.22
11:24
Там,скорее,проблема с передачей utf-8 обратно в 1с,так как для этого строку нужно специально готовить - каждый байт из utf-8 нужно преобразовать в двухбайтовое представление согласно win-1251 to unicode.
Тогда полученная в 7.7 строка будет записана в utf-8.
32 НЕА123
 
03.03.22
11:38
33 zenon46
 
03.03.22
11:57
(32) жаль имени файла нет, через гугл я не смог найти
34 Злопчинский
 
03.03.22
18:43
В формексе есть кодирование утф8 но только в одну сторону
Компьютер — устройство, разработанное для ускорения и автоматизации человеческих ошибок.