Эпичный нежданчик с RawByteString

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Эпичный нежданчик с RawByteString

Сообщение Cheb » 11.01.2018 18:33:46

Осваиваю fpc 3.0.4.
RawByteString призвана сохранить кодировку строк при написании "универсальных" функций, у которых кодировка на выходе такая же, как на входе, а работают с данными как с сфрыми байтами.
Вот и я тоже, написал свои Explode, Implode и милую
Код: Выделить всё
Function StrReplace (S, zamenjaemoe, zamenjajushee: RawByteString): RawByteString; overload;
var a: array of RawByteString;
begin
  a:= Explode(zamenjaemoe, s);
  Result:= Implode(zamenjajushee, a);
end;


-- и получил на выходе анус. Всё упало. :evil:

Вопрос на миллион баксов: какая кодировка у пустой строки?..
Прааавильно, cp1251 :evil: Хоть одна пустая строка затёсывается в работу с utf8 как с RawByteString - и всё исходит на говно.

Пришлось допатчить:
Код: Выделить всё
  function Implode(separator: RawByteString; a: RawByteStringArray): RawByteString; overload;
  var i, sl, al, l: integer;
  begin
    //a friendly reminder: strings in Pascal index from 1, not 0
    Result:= '';
    sl:= Length(separator);
    l:= 0;
    for i:=0 to High(a) do l+= Length(a[i]);
    l+= sl * (Length(a) - 1);

    SetLength(Result, l);
    l:= 0;
    for i:=0 to High(a) do begin
      if i > 0 then begin
        if sl > 0 then MOVE(separator[1], Result[l + 1], sl * SizeOf(separator[1])); //copying as a binary blob
        l+= sl;
      end;
      al:= Length(a[i]);
      if al > 0 then MOVE(a[i][1], Result[l + 1], al * Sizeof(separator[1]));
      l+= al;
    end;
    {$if FPC_FULLVERSION>30000}
    //assigns string's character set in FPC 3
   SetCodePage(Result, StringCodePage(separator), false);
    for i:= 0 to High(a) do
      // There is a HUGE pitfall in that an empty string's character set
      // is always system default
      // So we have to scan for an non-empty string
      if (a[i] <> '') then begin
        SetCodePage(Result, StringCodePage(a[i]), false);
        break;
      end;
    {$endif}
  end; 


Фрагмент, использующий это:
(TFileNameString = Utf8String в текущей инкарнации на всех платформах)
Код: Выделить всё
  function UnmangleFileName (a: TFileNameString): TFileNameString;
  begin
    Result:= StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(StrReplace(
      StrReplace(StrReplace(StrReplace(
      a,  '{$PLATFORM}', SystemSuffix),
             '{$HOMEDIR}', Mother^.State.HomePath),
                '{$INSDIR}', Mother^.State.InstallPath),
                  '{$USERNAME}', Mother^.State.UserName),
                    '{$APPDATA}', Mother^.State.AppDataDir),
                      '{$MODULE}', Mother^.State.ModuleBaseDir),
                        '{$CACHE}', Mother^.State.CacheDir),
                          '{$SAVES}', Mother^.State.SessionDir),
                            '{$EMPTY}', TFileNameString(''));
    Result:= OptiPath(ExtractFilePath(Result)) + ExtractFilename(Result);
  end;
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 675
Зарегистрирован: 06.06.2005 15:54:34

Re: Эпичный нежданчик с RawByteString

Сообщение скалогрыз » 11.01.2018 18:44:16

Cheb писал(а):Вопрос на миллион баксов: какая кодировка у пустой строки?..
Прааавильно, cp1251 Хоть одна пустая строка затёсывается в работу с utf8 как с RawByteString - и всё исходит на говно.

пустой строки? т.е. константы?
так тебе нужно исходники объявить как utf8 исходники!
Код: Выделить всё
{$codepage utf8}

(.. повторить попытку)
детали
скалогрыз
долгожитель
 
Сообщения: 1660
Зарегистрирован: 03.09.2008 02:36:48

Re: Эпичный нежданчик с RawByteString

Сообщение Cheb » 11.01.2018 18:59:44

Неееее. Utf8 cтрока бьётся на части. Первая часть оказывается пустой. Пустая строка - это NIL, и кодировку ей хранить негде. При попытке взять кодировку из неё и присвоить Result, получается cp1251

Я изначально делал с прицелом на фпц3 и у меня там было
Код: Выделить всё
if (Length(a) > 0) and (Length(a[0]) > 0) then Result:= COPY(a[0], 1, 1);
    //assigns string's character set in FPC 3

- а слона-то я и не приметил! Что будет, когда експлодишь строку, начинающуюся с разделителя? Первая в массиве будет пустой.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 675
Зарегистрирован: 06.06.2005 15:54:34

Re: Эпичный нежданчик с RawByteString

Сообщение скалогрыз » 11.01.2018 23:30:02

Cheb писал(а): Пустая строка - это NIL, и кодировку ей хранить негде.

чаво???
скалогрыз
долгожитель
 
Сообщения: 1660
Зарегистрирован: 03.09.2008 02:36:48

Re: Эпичный нежданчик с RawByteString

Сообщение runewalsh » 12.01.2018 00:37:28

Попробуй сделать в начале программы DefaultSystemCodePage := (нужная кодировка). Не уверен, как это будет работать с «настоящей» кодировкой, но мне, например, DefaultSystemCodePage := CP_ACP помогла работать с типом string так, как я это всегда делал — как с сырой последовательностью байт без какой-либо магии кодировок (ну, по крайней мере пока строки исключительно string). (Я бы использовал более идиоматичный CP_NONE, просто без UTF-8 BOM и {$codepage} строковым литералам выставляется именно CP_ACP, так что в моём случае при их конкатенации с динамически созданными строками, которым выставлена DefaultSystemCodePage, RTL видит, что у обоих «типа» одинаковая кодировка, и тихо ничего не трогает).
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 405
Зарегистрирован: 27.04.2010 00:15:25

Re: Эпичный нежданчик с RawByteString

Сообщение zub » 12.01.2018 00:59:40

Это не нежданчик, пустая строка имеет кодировку DefaultSystemCodePage
Код: Выделить всё
program Project1;

procedure ShowCodepage(s:String);
begin
  WriteLn(StringCodePage(s));
end;

begin
  //DefaultSystemCodePage:= CP_ACP;
  WriteLn(DefaultSystemCodePage);
  ShowCodepage('');
  ShowCodepage('test');
  readln;
end.
zub
долгожитель
 
Сообщения: 2424
Зарегистрирован: 14.11.2005 23:51:26

Re: Эпичный нежданчик с RawByteString

Сообщение Cheb » 12.01.2018 01:34:30

Это не нежданчик,

Да, но для этого надо сначала прочесть документацию! :shock:
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 675
Зарегистрирован: 06.06.2005 15:54:34

Re: Эпичный нежданчик с RawByteString

Сообщение serbod » 12.01.2018 17:12:32

SetCodePage(Result, StringCodePage(separator), false);
...
SetCodePage(Result, StringCodePage(a[i]), false);

Зачем так делать? Либо что-то одно.
Аватара пользователя
serbod
постоялец
 
Сообщения: 308
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Эпичный нежданчик с RawByteString

Сообщение Cheb » 13.01.2018 05:03:23

Зачем так делать?

На случай, если цикл не выполнится ни одного раза ИЛИ все строки в массиве - пустые?
Без перекодировки цена этого действия нулевая, присвоить одно целое.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 675
Зарегистрирован: 06.06.2005 15:54:34


Вернуться в Free Pascal Compiler

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

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

Рейтинг@Mail.ru