Забавный но досадный глюк

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

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

Re: Забавный но досадный глюк

Сообщение hovadur » 17.04.2013 15:31:54

alexey38 писал(а): операция "c8:=utf8[j]" не является операцией получения литерала в кодировке UTF8

Да, я согласен. А ты согласись, что "с8:=utf8[j]" правильная операция, если мы ищем обычный пробел.
alexey38 писал(а):Вы так и не можете ответить каким образом Вы догадываетесь или программа должна догадаться,

Не надо гадать, UTF8 без BOM и точка. Если не так, то программа неверно будет отображать данные, и человек сам сконвертит как надо.
alexey38 писал(а):Для использования утилиты iconv нужно указать параметры, как Вы догадываетесь какие параметры нужно указать?

Вот тут нужно гадать. Если он из русской Windows, то cp1251 или koi8r, если из французской Windows, то iso8859. И т.д.
alexey38 писал(а):Как решить эту проблему Вы так и не смогли ответить.

Не нужно решать эту проблему. UTF8 без BOM и точка. Программа понимает только UTF8 без BOM
alexey38 писал(а):Вы должны были в тесте исключить конвертацию строки "utf8 := AnsiToUtf8(ansi);", но это не сделали

Так никакой конвертации на самом деле не происходит. utf8 это и есть ansistring.
hovadur
постоялец
 
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Re: Забавный но досадный глюк

Сообщение alexey38 » 17.04.2013 16:08:31

hovadur писал(а):Не надо гадать, UTF8 без BOM и точка. Если не так, то программа неверно будет отображать данные, и человек сам сконвертит как надо.

Вы либо тормоз, либо таким прикидываетесь. Есть файл, Вы не знаете в каком он формате, т.к. в его имени этого не сказано, ВОМ нет, как Вы и говорите. Как определите, что это файл UTF8? Как программа должна это сделать, например, программа iconv, чтобы не делать неправильных преобразований?

Я конечно понимаю, что любой анализ можно делать вручную, можно выкинуть комп и считать на счетах, можно для определения кодировки текстового файла использовать мозги человека. Но зачем тогда комп, если для рутинной операции нужен человек?

Добавлено спустя 19 минут 21 секунду:
hovadur писал(а):Да, я согласен. А ты согласись, что "с8:=utf8[j]" правильная операция, если мы ищем обычный пробел.

Если мне задали задачу решить пример "сколько будет 2+2?", а я в ответе напишу "10-6=4", будет ли это верным ответом на поставленную задачу? Результаты же совпали.

Во-первых, Вы допустили смысловую ошибку, присвоив в переменную с типом UTF8String из другой строки UTF8String символ (AnsiChar), тем самым введя в заблуждение. С точки зрения кодировки UTF8 переменная с8 будет содержать непонятно что.
Во-вторых, с точки зрения самого тестирования, вместо того, чтобы символ (AnsiChar) сравнивать с кодом символа пробела, вы сделали присвоение символа ANSI в строку UTF8String, что требует лишнего времени. В итоге Вы получили искаженный результат в части быстродействия. Вы получили замедление в 33 раза, вместо того, чтобы получить замедление в 1,5 раза. В моем примере я получал в UTF8String (AnsiString) литерал в кодировке UTF8. В Вашем варианте Вы не получали литерала, и для чего тогда использовали строковый, а не символьный тип?

Добавлено спустя 13 минут 58 секунд:
hovadur писал(а):Так никакой конвертации на самом деле не происходит. utf8 это и есть ansistring.

Опять ошибаетесь. Посмотрите на Length(utf8) и Length(ansi) в указанном примере.

Вышеуказанные уже систематические ошибки говорят, что Вы не только "пальцегнуты", но еще и банально не умеете программировать. Зато встревать в темы, в которых плаваете Вы мастер, тут у Вас не отнимешь дара. У меня возникло подоозрение, когда Вы настойчиво требовали примеров, вместо того, чтобы привести свой пример. Теперь понятно, Вы тогда просто не сумели написать свой пример, вот SeZuka - он смог за 5 минут. А Вы только языком можете. Все ясно.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Забавный но досадный глюк

Сообщение debi12345 » 17.04.2013 17:04:43

utf8 это и есть ansistring.

Потому что сырятина мама не горюй :)

length(ansistring) = число символов, мгновенно читается из "заголовка" строки

length(utf8) = число символов можно выяснить только после полного обхода строки, по ходу разбираясь с комбосимволами. Хранить в заголовке тоже не выход - потому что придется пересчитывать этот заголовок после каждого изменения (не удаленеи и не добавления) в строке.
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение alexey38 » 17.04.2013 17:41:06

debi12345 писал(а):length(utf8)

Команда length(utf8) выдает число байт (из заголовка), а UTF8Length(utf8) число литералов, уже путем парсинга.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Забавный но досадный глюк

Сообщение hovadur » 17.04.2013 17:43:19

alexey38 писал(а):Теперь понятно, Вы тогда просто не сумели написать свой пример

У меня клавиатура дома сломалась, и поэтому так долго шло программирование примера.
alexey38 писал(а):Как программа должна это сделать, например, программа iconv, чтобы не делать неправильных преобразований?

Программа iconv должна иметь параметр, чтобы понимать из чего ей делать преобразование. Сама она не должна решать какая кодировка. Конечно у нее есть некоторые эвристики, но на то они и эвристики, чтобы не полагаться на них.
alexey38 писал(а):Опять ошибаетесь.

Хорошо, c8 должно быть AnsiChar, чтобы конвертации не было из AnsiChar в AnsiString. Если убрать эту конвертацию, то никаких других конвертаций не делается, так как UTF8String есть AnsiString.
alexey38 писал(а):Посмотрите на Length(utf8) и Length(ansi) в указанном примере.

Потому что мы делаем преобразование utf8 := AnsiToUtf8(ansi), utf8 увеличивается, но utf8 не перестает быть ansistring.
debi12345 писал(а):число символов можно выяснить только после полного обхода строки

Неверно, программа не делает полного обхода строки, так как utf8string есть ansistring, и length(utf8) это кол-во байт, а UTF8Length(utf8) - это кол-во символов. Ты, наверное, хотел сказать:
utf8length(utf8) = число символов можно выяснить только после полного обхода строки, по ходу разбираясь с комбосимволами


Добавлено спустя 1 минуту 31 секунду:
alexey38 писал(а):А Вы только языком можете.

Странно, у меня сложилось о тебе такое же впечатление, у меня клавиатура хотя бы сломалась, а у тебя что?
hovadur
постоялец
 
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Re: Забавный но досадный глюк

Сообщение alexey38 » 17.04.2013 18:43:36

hovadur писал(а):Потому что мы делаем преобразование utf8 := AnsiToUtf8(ansi), utf8 увеличивается, но utf8 не перестает быть ansistring.

Но Вы сказали "Так никакой конвертации на самом деле не происходит. utf8 это и есть ansistring.", в ответ на мою фразу "Вы должны были в тесте исключить конвертацию строки "utf8 := AnsiToUtf8(ansi);", но это не сделали".

Если Вы хотели показать существования быстрого алгоритма для данного теста подсчета пробелов, то самый просто был бы просто перебор исходной строки ansi.
UTF8String = ansistring, тип ansistring - это тип, и не более, и ansi в нем ничего не значит. Но программирование - это не просто способ формирования исполняемого файла, поэтому есть и стилистика и прочие правила. UTF8String - означает, что мы информируем себя и других о том, что по смыслу в переменной будет именно UTF8. А написав AnsiString мы информируем себя и других о том, что по смыслу в переменной будет 8-битовая строка в некой кодировке (cp1251 и т.п.). Бинарный код одинаковый, а смысловая нагрузка разная

Добавлено спустя 3 минуты 5 секунд:
hovadur писал(а):У меня клавиатура дома сломалась, и поэтому так долго шло программирование примера.

А за язык тогда кто тянул? Вы же не вопросы задавали. Вы голословно оспаривали то, что в итоге было подтверждено тестами. Вы сомневались, значить Вам нужно доказывать свою позицию, как говорится презумпция невиновности.

Добавлено спустя 15 минут 10 секунд:
hovadur писал(а):Программа iconv должна иметь параметр, чтобы понимать из чего ей делать преобразование. Сама она не должна решать какая кодировка. Конечно у нее есть некоторые эвристики, но на то они и эвристики, чтобы не полагаться на них.

Конкретно iconv должна иметь параметр, который вынужден вручную задать пользователь. Для чего обременять пользователя во всех случаях вопросами? Когда линоховский комп используется для простых стандартных задач, то обычно нет проблем, т.к. и не требуется работать с тестовыми файлами. Но есть масса задач, где и проги не из репозитария, и файлов целая куча, и новые и старые данные и т.п. Это любая производственная задача. Вы задолбаетесь учить юзера конвертить файлы, задолбаетесь его обучать определять какие бывают кодировки.

Отсутствие ВОМ - это искусственно созданная проблема (ленью американских программеров), и для ее решения нужно прикладывать героические усилия. Проблем обычно нет в тех случаях, когда и комп не сильно-то нужен, да и любая ОС может решить эту задачу.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Забавный но досадный глюк

Сообщение Alex2013 » 17.04.2013 19:02:41

Насчет "вечного сака с гвоздями для авторов" UTF-8... Главным недостатком является НАЗВАНИЕ по нему совершенно не возможно догадаться что формат не 8-битный
Назвали бы UTF-8+ а так даже в голову не приходит (Я думал что формат включает в себя спец символ переключения кодовых страниц уникода что было-бы логично ).

Но это теория а практика такая
1 Как заставить лазарус работать с обычной 8-битной кодировкой ?
(Исходники ерунда а вот обработку неплохо бы сделать в обычной cp1251 )

2 В чистом фрипаскале зачаточности на UTF-8 нет
(Несколько лет возился с проектом ХайАсм (hiasm.com) в качестве одного из компиляторов использующего FPC с utf не столкнулся ни разу)
А тут кажется даже весь текстовый ввод-вывод в UTF8
Вывод напрашивается; возможно существует возможность настроить лазарус для
работы с cp1251 (или кои8 для линукса)
:idea:

Если же придется обрабатывать внешние данные в UTF-8 то их нетрудно пере конвертировать.

зы
UTF-32 это пока что избыточная экзтика .
Кстати мысль ! А нельзя-ли предложить некий True-СodU8 ?
С переключением страниц
(То есть встречается в тексте ~cp1251 а дальше идет русский текст встречается ~China1 и пошли иероглифы не хватит ~China1 вызвать хоть ~China999 но файл останется 8-бит и парсинг нужен минимальный ..)
Или возможно такой уже существует ?
Последний раз редактировалось Alex2013 17.04.2013 19:12:23, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 3145
Зарегистрирован: 03.04.2013 11:59:44

Re: Забавный но досадный глюк

Сообщение hovadur » 17.04.2013 19:05:36

alexey38 писал(а):Но Вы сказали

Понял, маразм попутал, извините, пожалуйста. Я думал, что "utf8 := AnsiString(ansi)", а не "utf8 := AnsiToUtf8(ansi)"
alexey38 писал(а):Бинарный код одинаковый, а смысловая нагрузка разная

Согласен, только ради этого.
alexey38 писал(а):А за язык тогда кто тянул?

А я и не болтал в это время. 8-го числа я отключился, и набирал лишь несколько фраз, вроде "у тебя есть примеры таких программ?", с помощью экранной клавиатуры. Появился я только 16 числа, начав с обсуждения UTF8Copy.
Так что у тебя-то сломалось, что не предоставил пример ты?
hovadur
постоялец
 
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Re: Забавный но досадный глюк

Сообщение bormant » 17.04.2013 22:13:49

alexey38 писал(а):вместо пробелов нужно было подсчитывать число букв "Я"

Код: Выделить всё
UTF-8:  4527 entries in 152277 ticks.
UTF-16: 4527 entries in 21559 ticks.
UTF-32: 4527 entries in 17249 ticks.
152277/17249 = 8,8 раз.

Код: Выделить всё
var
...
  p: PChar;
...
  c8 := #$D0#$AF; // 'Я' in utf8
 
  { UTF-8 test }
  QueryPerformanceCounter(t1);
  TestCount := 0;
  for i := 1 to TRIES do begin
    p := @utf8[1];
    while true do begin
      p := StrPos(p, @c8[1]);
      if p = nil then break;
      Inc(p); Inc(TestCount);
    end;
  end;
  QueryPerformanceCounter(t2);
  WriteLn('UTF-8:  ', TestCount, ' entries in ', t2 - t1, ' ticks.');
...
Аватара пользователя
bormant
постоялец
 
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Re: Забавный но досадный глюк

Сообщение hovadur » 17.04.2013 22:26:04

bormantвыложи, пожалуйста, весь код, мне тоже интересно, как такое возможно

Добавлено спустя 8 минут 55 секунд:
хм... А TRIES у тебя чему равно?
hovadur
постоялец
 
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Re: Забавный но досадный глюк

Сообщение bormant » 17.04.2013 22:45:10

Я менял только код для UTF-8, остальное как было в приведённом в теме примере. Суть иллюстрации в том, что для поиска корректного символа в UTF-8 посимвольный разбор UTF-8 строки не нужен (by design).
Код: Выделить всё
{$H+,R-}
uses SysUtils, Windows;//strings;
const
  TRIES = 1;
  CAPACITY = 1000000;
var
  ansi: AnsiString;
  utf8: Utf8String;
  i, j: LongWord;
  t1, t2: Int64;
  p: PChar;
  utf16: UnicodeString;
  utf32: UCS4String;
  TestCount: LongWord;
  c8:  AnsiString;
  c16: UCS2Char;
  c32: UCS4Char;

begin
  //Randomize;
  SetLength(ansi, CAPACITY);
  for j := 1 to CAPACITY do
    ansi[j] := Char(32 + Random(256 - 32));
  utf8 := AnsiToUtf8(ansi);
  c8 := #$D0#$AF; // 'Я' in utf8
 
  { UTF-8 test }
  QueryPerformanceCounter(t1);
  TestCount := 0;
  for i := 1 to TRIES do begin
    p := @utf8[1];
    while true do begin
      p := StrPos(p, @c8[1]);
      if p = nil then break;
      Inc(p); Inc(TestCount);
    end;
  end;
  QueryPerformanceCounter(t2);
  WriteLn('UTF-8:  ', TestCount, ' entries in ', t2 - t1, ' ticks.');
 
  { UTF-16 test }
  utf16 := UTF8Decode(UTF8);//**
  QueryPerformanceCounter(t1);
  TestCount := 0;
  for i := 1 to TRIES do begin
    for j := 1 to Length(utf16) do begin
      c16 := utf16[j];
      if c16 = #$042F then Inc(TestCount);
    end;
  end;
  QueryPerformanceCounter(t2);
  WriteLn('UTF-16: ', TestCount, ' entries in ', t2 - t1, ' ticks.');

  { UTF-32 test }
  utf32 := UnicodeStringToUCS4String(utf16);//**
  QueryPerformanceCounter(t1);
  TestCount := 0;
  for i := 1 to TRIES do begin
    for j := 0 to Length(utf32) - 1 do begin
      c32 := utf32[j];
      if c32 = $042F then Inc(TestCount);
    end;
  end;
  QueryPerformanceCounter(t2);
  WriteLn('UTF-32: ', TestCount, ' entries in ', t2 - t1, ' ticks.');
end.


Для 100 прогонов по строке из 1e6 символов отношение немногим лучше -- 7,8 раз
Код: Выделить всё
UTF-8:  452700 entries in 13420536 ticks.
UTF-16: 452700 entries in 2151442 ticks.
UTF-32: 452700 entries in 1724320 ticks.


Добавлено спустя 4 минуты 37 секунд:
Если убрать паразитные присваивания для UTF-16 и UTF-32, то прогон 100 х 1e6 станет выглядеть так
Код: Выделить всё
UTF-8:  452700 entries in 13474179 ticks.
UTF-16: 452700 entries in 1385488 ticks.
UTF-32: 452700 entries in 1207294 ticks.
то есть примерно в 11 раз.

Максимальный проигрыш будет на строке, состоящих из одних только искомых "Я" (де-факто сведётся к посимвольному перебору):
Код: Выделить всё
UTF-8:  10000000 entries in 4897311 ticks.
UTF-16: 10000000 entries in 142763 ticks.
UTF-32: 10000000 entries in 143597 ticks.
Последний раз редактировалось bormant 17.04.2013 22:57:56, всего редактировалось 1 раз.
Аватара пользователя
bormant
постоялец
 
Сообщения: 408
Зарегистрирован: 21.03.2012 11:26:01

Re: Забавный но досадный глюк

Сообщение Sergei I. Gorelkin » 17.04.2013 22:51:39

bormant писал(а):152277/17249 = 8,8 раз

При том, что реализация StrPos для i386 (точнее, того что она вызывает - StrLComp и StrScan; сама StrPos одна для всех платформ) страшна как ядерная война, на других платформах разница почти наверняка будет меньше.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Забавный но досадный глюк

Сообщение hovadur » 17.04.2013 23:00:00

вместо "p := @utf8[1]" должно быть "p := @utf8[i]"?
hovadur
постоялец
 
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Re: Забавный но досадный глюк

Сообщение debi12345 » 17.04.2013 23:02:22

на других платформах разница почти наверняка будет меньше.

Ну да - на 1% инсталляций результат будет например 5 раз :)
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Re: Забавный но досадный глюк

Сообщение Sergei I. Gorelkin » 17.04.2013 23:05:08

Ну почему же 1%, x86_64 все-таки несколько шире распространена...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Пред.След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru