суббота, 9 апреля 2016 г.

Проверка строки на "списочность"

В конференции CACHE_RU проходило обсуждение вопроса о возможности определить является ли строка корректным списком CACHE'. Было выяснено при обобщении информации поступившей из различных источников, что
  • Можно сформировать строку произвольного содержания, не пользуясь списковыми функциями
  • Строка, сформированная списковыми функциями, ими же обрабатывается корректно
  • В ситуации, когда строка сформирована несписковыми функциями, в некоторых случаях она может некоторыми функциями как список, а другими как не список
  • Существуют строки, при определении которых на списочность процесс завершается аварийно
  • Существуют программы, которые не могут определить происхождение строки и была ли она сформирована списковыми функциями или нет
  • Спустя некоторое время представители фирмы Интерсистемс сообщили, что исправления проблемы войдут в билд 5.0.5 и более поздние. Выдержка из внутренней технической документации:
    Prodlog Item 34439  Edited by Sorenson,Chuck
    ------------------------------------------------------------
    MOST RECENT CHANGES:
    4) 2003-10-31 16:58:09 Modified by Sorenson,Chuck
    DEVCHANGE changed to: CDS346
    FIXER changed from: Unknown  to: Sorenson,Chuck
    STATUS changed from: Dev  to: Test
    
    COMMENT:
    I ported CDS346 and CDS405 to 5.0.6 build 1006
    and 5.0.5 build 912.
    
  • После довольно бурного обсуждения проблемы вопрос был объявлен модератором группы оффтопиком, поэтому все последующие его обсуждения следует производить вне группы CACHE_RU.
Собственно, это и было причиной появления этой заметки.


Определить строение строки, формируемой списковыми функциями, не составляет большого труда, если воспользоваться командой zzdump. Просмотрев различные варианты списков, можно заметить, что список является конкатенацией тего-организованных структур, где каждый элемент начинается с длины, потом идет тип элемента, потом само значение, причем различные типы кодируются различным образом. Очевидно, это сделано с целью уменьшения объемов хранения. Списки оказались очень эффективны и применяются повсеместно. После некоторых размышлений я составил небольшую программку, определяющую является ли строка списком или нет. Программа составлена на М и проверялась на версии 3.2.2
LL(val) ; вернуть длину списка если это список или -1 если нет
 i val="" q 0
 n ret,i,sym,done,itemlen
 s ret=0,done=0,i=1
 f  q:done  d
 . s sym=$e(val,i)
 . i sym="" s done=1 q
 . i sym=$c(0) d
 . . s sym=$e(val,i+1) i sym="" s done=1,ret=-1 q
 . . s itemlen=$a(sym)
 . . s sym=$e(val,i+2) i sym="" s done=1,ret=-1 q
 . . s itemlen=itemlen+($a(sym)*256)
 . . s sym=$e(val,i+3) i sym="" s done=1,ret=-1 q
 . . i $a(sym)>7 s done=1,ret=-1 q
 . . i $e(val,i+4)="" s done=1,ret=-1 q
 . e  d
 . . s itemlen=$a(sym)
 . . q:itemlen=1
 . . s sym=$e(val,i+1) i sym="" s done=1,ret=-1 q
 . . i $a(sym)>7 s done=1,ret=-1 q
 . . i ($a(sym)'=4)&($a(sym)'=1)&($a(sym)'=5) s sym=$e(val,i+2)
 . . i sym="" s done=1,ret=-1 q
 . q:done
 . i $l($e(val,i,i+itemlen-1))<itemlen s done=1,ret=-1 q
 . s i=i+itemlen
 . s ret=ret+1
 q ret
Функция составлялась не в расчете на производительность работы, а на читабельность. Эта функция проверялась на наборе строк, которые и вызвали к жизни проблему, и на них показала правильные результаты. Если у Вас есть строки, которые штатными функциями определяются неправильно, то просьба проверить на них эту функцию.

Сама функция не производит детальный анализ строки, например строка
s str=$E($LB(1.2),1,3) s $e(str,1)=$c(3)
определяется как список из одного элемента, но эта строка не может быть получена списковыми функциями:
USER>zzdump str
0000: 03 06 FF
USER>w $li(str)
0
USER>zzdump $lb(0)
0000: 02 04
USER>zzdump $lb("0")
0000: 03 01 30
USER>zzdump $lb(0.0)
0000: 02 04
USER>w $listsame(str,$lb(0))
1
То есть при этом тем не менее списковые операции признают ее корректным списком из одного элемента число 0. Вполне возможно, что в некоторых случаях может понадобиться также и детальный анализ содержания элемента, например на предмет возможности его сформировать списковыми функциями.

В целом же, в силу возможности применить функции $C() в любых вариантах, нет возможности точно сказать, была ли строка получена списковыми функциями или она так получилась в силу каких-то обстоятельств. В тех случаях, когда программа просмотра данных определит, что строка является корректным списком, но по контексту работы она получалась не списковыми операциями, программа может показать несписковую переменную как списковую. От такой проблемы, видимо, могут помочь только административные меры. Например, программа просмотра должна знать, что в определенных местах данные всегда не являются списками.

И, как обычно, если с приведенными мной кодами возникнут проблемы, прошу сообщить мне об этом.

Алексей Маслов (СП.АРМ, Санкт-Петербург) нашел ошибку в определении списочности списка $lb(-1), исправление внесено в код.

Комментариев нет:

Отправить комментарий