Мистика Copy

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Мистика Copy

Сообщение lordgray » 14.03.2016 13:32:33

err_copy.png
Здравствуйте! Спасите от сумасшествия, почти сутки бьюсь над загадкой "детской", где ее и быть не должно!
На скриншоте отладка кода и окно слежения за переменными.
Мистика в строке 1470. Там Copy ! Значение исходной строки t := 'locale=409', копируется первых 7 символов, и получается 'loca' ! Это как? :shock:
1) в 'locale=407' все символы английские;
2) никаких потоков, которые могли бы что-то изменить, нет;
3) Win7x64, Lazarus 1.6x64 (не RC2, а нормальный, последний), fpc 3.0.0, программа компилится в 32 бита.
4) Вариант, что отладчик не показывает строку полностью, не проходит, т.к. следующая строка - IF, который подтверждает, что значение 'loca'
Что делать? Менял Copy(t, 1, i) на Copy(t, 1, 7), результат тот же.
Капец, этих Copy по программе, штук 20, если не больше, и везде работают нормально, а тут - хрень какая-то.
lordgray
новенький
 
Сообщения: 60
Зарегистрирован: 10.10.2010 00:19:11

Re: Мистика Copy

Сообщение wavebvg » 14.03.2016 14:23:59

Можно предположить, что строка хранится в UnicodeString или чем-то подобном.
А умная среда разработки Вам помогает и не заставляет думать о кодировках.

Попробуйте SetCodePage над строчкой перед сравнением.
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: Мистика Copy

Сообщение DYUMON » 14.03.2016 14:28:37

что лежит в paramname ?
Аватара пользователя
DYUMON
постоялец
 
Сообщения: 234
Зарегистрирован: 11.03.2009 13:32:54

Re: Мистика Copy

Сообщение lordgray » 14.03.2016 14:32:35

DYUMON писал(а):что лежит в paramname ?


Код: Выделить всё
const
  ParamName = {$ifdef windows}'locale'{$else}'llocale'{$endif};


Добавлено спустя 5 минут 43 секунды:
wavebvg писал(а):Можно предположить, что строка хранится в UnicodeString или чем-то подобном.
А умная среда разработки Вам помогает и не заставляет думать о кодировках.

Попробуйте SetCodePage над строчкой перед сравнением.

1) String заменил на UTF8String - безрезультатно
2) Вернул на String. Вызов SetCodePage ругается на несоответствие типов: нужен RawByteString, а передается AnsiString
lordgray
новенький
 
Сообщения: 60
Зарегистрирован: 10.10.2010 00:19:11

Re: Мистика Copy

Сообщение wavebvg » 14.03.2016 18:53:34

Я предполагаю, что кодировка в ParamName - однобайтовая, а в Loc - двубайтовая.
Для решения проблемы необходимо переконвертировать все строки с одну кодировку.
Учтите магию из вот этой статьй:

http://www.freepascal.ru/article/freepa ... 0718142000
А именно:
Код: Выделить всё
r1:=ac1;            // ac1 65001 -> r1 65001
r1:=ac1+ac3;     // ac1 65001 ac3 1251 -> r1 1251 при начальной инициализации
r1:=ac1+ac3;     // r1 65001 ac1 65001 ac3 1251 -> r1 65001 при повторном присвоении
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: Мистика Copy

Сообщение lordgray » 14.03.2016 18:59:25

wavebvg писал(а):Можно предположить, что строка хранится в UnicodeString


Спасибо!!!
Функция Copy перегружаемая, и есть вариант под юникод. Видать, компилятор решил взять именно его (с каких делов?).
Объявил переменную t как UnicodeString, и все заработало.
Я, конечно, рад, что решилось, но изначально, до суток мучений, было:
Код: Выделить всё
Loc := Lang.Values['locale']

И это всегда возвращало пустую строку, не смотря на то, что строка 'locale=409', в Lang присутствовала.
Это уже разбираясь, что к чему, обвешал все переменными, повторяя поведение свойства Values, чтоб можно было отдебажить.
Что "перемкнуло" компилятор в данной функции, остается загадкой. И, буду надеяться, в других местах кода, его так не глюканет.
lordgray
новенький
 
Сообщения: 60
Зарегистрирован: 10.10.2010 00:19:11

Re: Мистика Copy

Сообщение bormant » 14.03.2016 20:59:06

lordgray писал(а):Значение исходной строки t := 'locale=409', копируется первых 7 символов, и получается 'loca' ! Это как?

Если у вас перед 'locale=409' был BOM, то он в UTF-8 занимает как раз 3 байта...
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Мистика Copy

Сообщение lordgray » 14.03.2016 21:30:35

bormant писал(а):Если у вас перед 'locale=409' был BOM, то он в UTF-8 занимает как раз 3 байта...

Знаете, мне тоже приходила такая мысль. Да, BOM есть. Но! Если бы я работал напрямую с текстовым файлом, то да, это было бы верно. Но файл грузит TStringList. Он определяет BOM, и обрезает его. Кроме того, для Lang[1], Lang[2] все тоже самое происходит! Тут уже на BOM не спишешь.

Я все думал, в чем разница этого кода, и всего остального, раскиданного по программе, где все работает как надо. И заметил одно отличие: этот код (процедура), вызывается из Initialization секции. Вполне возможно, что этот Initialization вызван раньше, чем Initialization модуля, где инициализируется StringManager. Мне кажется логичным такой вариант. Буду проверять. Как вариант, поставить модуть последним в USES, либо код перенести в OnCreate модуля данных. Как проверю, отпишусь. Быстрее всего, уже завтра.

Спустя 2 часа:
Перестановка модуля в USES, не дала результата, вызов функции из OnCreate модуля данных, тоже ничего не изменил.
Я в шоке: объявлял все строковые переменные, как AnsiString, UTF8String, String, даже ShortString, пофигу, Copy обрабатывает как 2-х байтную строку. Пытался Copy(AnsiString(t),... тоже не помогло. Открыл окно ассемблера, и это меня поставило в полный тупик: ассемблер показывает вызов fpc_ansistr_copy.
На этом мысли останавливаются.
lordgray
новенький
 
Сообщения: 60
Зарегистрирован: 10.10.2010 00:19:11

Re: Мистика Copy

Сообщение SSerge » 15.03.2016 03:58:40

lordgray писал(а):Он определяет BOM, и обрезает его


Вы уверены? Я как-то в целях эксперимента с удивлением выяснил, что BOM прекрасно приписывается к строкам при чтении файлов
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Мистика Copy

Сообщение lordgray » 15.03.2016 09:19:08

SSerge писал(а):
lordgray писал(а):Он определяет BOM, и обрезает его


Вы уверены? Я как-то в целях эксперимента с удивлением выяснил, что BOM прекрасно приписывается к строкам при чтении файлов


Финиш. Сделал через LoadFromStream.
Copy заработал. Упростил до начального варианта, через свойство Value, и оно заработало.

Код: Выделить всё
var Loader: TFileStream;
    Lang: TStringList;
    Loc: String;
begin
  Lang := TStringList.Create;
  //Lang.LoadFromFile(aSt);
  Loader := TFileStream.Create(aSt, fmOpenRead);
  Loader.Position := 3;//skip BOM
  Lang.LoadFromStream(Loader);
  Loc := Lang.Value['locale'];


Спасибо, Вы мой спаситель.
Я попутал с BOM. Это Delphi его отслеживает. Сейчас глянул в исходник TStrings.LoadFromFile(LoadFromStream), там и намека на проверку BOM нет.
А что ж я напутал с Lang[2], Lang[3]? Блин, каша в голове.
Всем спасибо! Давно таких "приколов" не попадалось.
lordgray
новенький
 
Сообщения: 60
Зарегистрирован: 10.10.2010 00:19:11


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 29

Рейтинг@Mail.ru