URL Encoder - процентное кодирование

Вопросы программирования и использования среды Lazarus.

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

URL Encoder - процентное кодирование

Сообщение resident » 08.04.2016 16:39:34

Здравствуйте, мне нужно сделать процентное кодирование строки для получения URL. Решение нашел в синапсе, но уж больно оно древнее.
В теме про Lazarus 1.6 многие удивлялись: зачем нужен доступ к символу в строке по индексу? Мол и без него все хорошо.
Так вот все найденные мной решения процентного кодирования - отрыжка Delphi ({$MODE DELPHI}) с доступом к символам по индексу и прочими пережитками (проверка наличия во множестве символа - in и т.п.).
А существует ли вообще библиотека с модным UTF8 кодированием?
resident
энтузиаст
 
Сообщения: 605
Зарегистрирован: 13.03.2013 16:58:51

Re: URL Encoder - процентное кодирование

Сообщение Alex2013 » 08.04.2016 17:26:13

У меня вообще наверное ни одна программа без обращения к строке по индексу работать не сможет ... Удобно ведь... да UTF8 ну и что ?
Бред это ! Если так уж нужно перекодирую в Win-1251 обработаю и верну обратно в UTF8...
И вообще UTF8 уродливая пародия на UTF16 ! Нужно перейти на полностью 2 байтовую кодировку и забить болт на тупые костыли !
Alex2013
долгожитель
 
Сообщения: 2957
Зарегистрирован: 03.04.2013 11:59:44

Re: URL Encoder - процентное кодирование

Сообщение bormant » 08.04.2016 17:44:55

resident,
я вам одну простую вещь сейчас скажу: там, где используется URL-кодированная строка, ничего кроме ASCII в этом коде быть не может.
Или вы про посимвольный доступ к исходной строке? Вот тут не помню, URL-кодирование разве не побайтное?

http://en.wikipedia.org/wiki/Percent-encoding
Since the publication of RFC 1738 in 1994 it has been specified[1] that schemes that provide for the representation of binary data in a URI must divide the data into 8-bit bytes and percent-encode each byte in the same manner as above.
...
The generic URI syntax mandates that new URI schemes that provide for the representation of character data in a URI must, in effect, represent characters from the unreserved set without translation, and should convert all other characters to bytes according to UTF-8, and then percent-encode those values. This requirement was introduced in January 2005 with the publication of RFC 3986.
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: URL Encoder - процентное кодирование

Сообщение zub » 08.04.2016 18:11:28

>>А существует ли вообще библиотека с модным UTF8 кодированием?
Фу таким быть)) Сейчас в моду входит какраз UTF16 - в fpc уже появилось, в lcl пока нет

UTF8 - можно сказать "ретро" из старых, светлых времен 2.6.x))

По теме: не нужен посимвольный доступ. Используйте побайтовый. подсмотрите в педевикии что из себя представляет utf8 в байтах и вперед. Получится компактнее и думаю быстрее чем с "посимвольным".
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: URL Encoder - процентное кодирование

Сообщение Ichthyander » 08.04.2016 18:56:41

А чем решение в синапсе не понравилось? Я его всегда юзаю. Вкрай можно его доработать [и кинуть исходники автору :) ]
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 675
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: URL Encoder - процентное кодирование

Сообщение resident » 09.04.2016 17:00:53

bormant писал(а):Или вы про посимвольный доступ к исходной строке? Вот тут не помню, URL-кодирование разве не побайтное?

Так и есть.

zub писал(а):Сейчас в моду входит какраз UTF16 - в fpc уже появилось, в lcl пока нет

Внезапно. Чем они раньше думали, когда UTF8 согласовывали.

zub писал(а):Получится компактнее и думаю быстрее чем с "посимвольным".

Действительно, все решение в несколько строк получилось.

Код: Выделить всё
type
  TDoNotEncodeUsASCIICharsSet = set of Char;

function StrToPercentTriplet(const Str: string; const DoNotEncodeUsASCIICharsSet: TDoNotEncodeUsASCIICharsSet = []): string;
  var
    i: integer;
    ByteValue: integer;
  begin
    Result := '';
    for i := 1 to Length(Str) do
      begin
        ByteValue := Integer(Str[i]);
        if (ByteValue < 128) and (Str[i] in DoNotEncodeUsASCIICharsSet) then
          Result := Result + Str[i] else
          Result := Result + '%' + IntToHex(ByteValue, 2);
      end;
  end;

function StrToUrl(const Str: string): string;
  const
    UnreservedCharacters: set of Char = ['A'..'Z', 'a'..'z', '0'..'9', '-', '.', '_', '~'];
  begin
    Result := StrToPercentTriplet(Str, UnreservedCharacters);
  end;


Ichthyander писал(а):А чем решение в синапсе не понравилось?

1) Не удовлетворяет стандарту RFC 3986
2) Всякие Mode Delphi, Ansistring не хочу видеть, хочу чтоб все модно было.
resident
энтузиаст
 
Сообщения: 605
Зарегистрирован: 13.03.2013 16:58:51

Re: URL Encoder - процентное кодирование

Сообщение zub » 09.04.2016 17:58:19

>>хочу чтоб все модно было.
надо избавиться от конструкций типа
Код: Выделить всё
Result := Result + ...
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: URL Encoder - процентное кодирование

Сообщение resident » 09.04.2016 18:12:20

zub писал(а):надо избавиться от конструкций типа

Вредители какие-то.
Да ну к черту такую моду. :mrgreen:
http://listingimg.s3.amazonaws.com/DjFly-NashaRasha.mp3
resident
энтузиаст
 
Сообщения: 605
Зарегистрирован: 13.03.2013 16:58:51

Re: URL Encoder - процентное кодирование

Сообщение Лекс Айрин » 09.04.2016 19:08:04

zub, а по моему, очень удобно.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: URL Encoder - процентное кодирование

Сообщение zub » 09.04.2016 19:24:48

конечно удобно. но медленно
Такое "модно" было во времена string[255], но не с длинными строками
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: URL Encoder - процентное кодирование

Сообщение Лекс Айрин » 09.04.2016 19:34:58

zub, работа со строками никогда не была особо быстрой. Хотя со временем это становится не так актуально -- скорости растут.

Возможно, дело еще и в реализации самих библиотек работы со строками.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: URL Encoder - процентное кодирование

Сообщение zub » 09.04.2016 19:39:26

Такая "работа" конечно быстрой быть не может.
Если сделать нормально - будет на порядок быстрее

Добавлено спустя 1 час 43 минуты 28 секунд:
Вот собственно что у меня получилось:
Код: Выделить всё
program encodetest;
uses
  sysutils;
type
  TDoNotEncodeUsASCIICharsSet = set of Char;

function StrToPercentTriplet(const Str: string; const DoNotEncodeUsASCIICharsSet: TDoNotEncodeUsASCIICharsSet = []): string;
  var
    i: integer;
    ByteValue: integer;
  begin
    Result := '';
    for i := 1 to Length(Str) do
      begin
        ByteValue := ord(Str[i]);
        if (ByteValue < 128) and (Str[i] in DoNotEncodeUsASCIICharsSet) then
          Result := Result + Str[i] else
          Result := Result + '%' + IntToHex(ByteValue, 2);
      end;
  end;

function StrToUrl(const Str: string): string;
const
  UnreservedCharacters: set of Char = ['A'..'Z', 'a'..'z', '0'..'9', '-', '.', '_', '~'];
begin
  Result := StrToPercentTriplet(Str, UnreservedCharacters);
end;



function FastStrToPercentTriplet(const Str: string;var ResultString:string; const DoNotEncodeUsASCIICharsSet: TDoNotEncodeUsASCIICharsSet = []): integer;
const
  _Hex:array[0..15] of char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
var
  i: integer;
  ByteValue: byte;
begin
  result:=1;
  for i := 1 to Length(Str) do
    begin
      ByteValue := ord(Str[i]);
      if (ByteValue < 128) and (Str[i] in DoNotEncodeUsASCIICharsSet)
      then
        begin
          if length(ResultString)>0 then
             ResultString[result]:=Str[i];
          inc(result);
        end
      else
        begin
          if length(ResultString)>0
          then
            begin
             ResultString[result]:='%';
             inc(result);
             ResultString[result]:=_Hex[(ByteValue and $f0) shr 4];
             inc(result);
             ResultString[result]:=_Hex[ByteValue and $0f];;
             inc(result);
            end
          else
            inc(result,3);
        end;
    end;
end;

function FastStrToUrl(const Str: string;var ResultString:string): string;
const
  UnreservedCharacters: set of Char = ['A'..'Z', 'a'..'z', '0'..'9', '-', '.', '_', '~'];
var
  Resultlength:integer;
begin
  ResultString:='';
  Resultlength := FastStrToPercentTriplet(Str,ResultString,UnreservedCharacters);
  setlength(ResultString,Resultlength);
  FastStrToPercentTriplet(Str,ResultString,UnreservedCharacters);
end;

function CallLevNikolayevichTolstoy:string;
var
  fhandle,filelength:integer;
begin
  fhandle:=fileopen('warandpeace.txt',fmShareDenyNone);
  filelength:=FileSeek(fhandle,0,2);
  FileSeek(fhandle,0,0);
  setlength(result,filelength);
  FileRead(fhandle,result[1],filelength);
  fileclose(fhandle)
end;

var
  WarAndPeace,EncodedWarAndPeace:string;
  Time:TDateTime;
begin
  WarAndPeace:=CallLevNikolayevichTolstoy;

  time:=now;
  EncodedWarAndPeace:=StrToUrl(WarAndPeace);
  writeln('StrToUrl ',((now-time)*10e4):2:3,'sec');

  EncodedWarAndPeace:='';

  time:=now;
  EncodedWarAndPeace:=FastStrToUrl(WarAndPeace,EncodedWarAndPeace);
  writeln('FastStrToUrl ',((now-time)*10e4):2:3,'sec');
end.

Преобразование байта в хекс сделано навскидку, не прверял, если и неправильно - на скорость это не влияет. Рядом с ексешником должен лежать файл warandpeace.txt с чемто большим в UTF8, я для теста юзал войну и мир Толстого.
результат налицо))
E:\encodetest>encodetest.exe
StrToUrl 0.279sec
FastStrToUrl 0.020sec

Смысл в том чтоб не прибавлять по байтику, а сделать 2 прохода. в первом посчитать длину строки с результатом, во втором присваивать байтики в уже созданую строку
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26


Вернуться в Lazarus

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

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

Рейтинг@Mail.ru