Можно ли использовать AWK для распределения параметров внутри файла JSON?

1 )Очень простой (, но очень легкий ):с использованием cmp и для побайтового сравнения файлов ("binary diff" ). Дает количество различных байтов. Только что попробовал на нуле, работает.

cmp -l 1.jpg 2.jpg 2>/dev/null | wc -l

но это больше связано с файлом, чем с изображением -мудро...

Поэтому, если у вас есть доступ к Python на вашем компьютере, (извините, у меня нет такого дистрибутива на моем нулевом rpi, поэтому я не могу протестировать...):

2 )SSIM -Пакет PIL Python, основанный на структурном сходстве.(https://pypi.org/project/SSIM-PIL/). Ориентировано ли изображение таким образом, что по сравнению с первым решением оно должно давать меньше «ложных различий», то есть результат будет ближе к тому, что видит человеческий глаз.https://fr.wikipedia.org/wiki/Structural_Similarity

0
19.06.2021, 02:24
5 ответов

В языке TXR мы могли бы сделать это так:

$ txr data.txr data
[{"title":"A random Title 1","body":"1- a block of text that can contain any character\nand it  also can contain multiple lines"},
 {"title":"A random Title 2","body":"2- a block of text that can contain any character\nand it  also can contain multiple lines"},
 {"title":"A random Title 3","body":"3- a block of text that can contain any character\nand it  also can contain multiple lines"}]

Если код в data.txrравен:

@(bind vec @(vec))
@(repeat)
@title
BLOCK
@(collect)
@lines
@(until)
BLOCK
@(end)
@(cat lines "\n")
@(do (vec-push vec #J^{"title" : ~title, "body" : ~lines}))
@(end)
@(do (put-jsonl vec))

Мы создаем вектор хэшей :базовой структуры данных, соответствующей желаемому JSON.

Префикс #Jуказывает литерал JSON, встроенный в Lisp. Здесь у нас есть ^, указывающий на то, что литерал заключен в квазикавычки; ~символы обозначают символы без кавычек, которые вставляют значения в шаблон, :заголовок и выражение, которое вычисляет тело из собранных строк, соединяющих строки с новой строкой.

put-jsonlозначает put-jsonс символом новой строки после него. По умолчанию в потоке *stdout*.

Рекомендуется отступ, который выглядит следующим образом:

@(bind vec @(vec))
@(repeat)
@  title
BLOCK
@  (collect)
@    lines
@  (until)
BLOCK
@  (end)
@  (cat lines "\n")
@  (do (vec-push vec #J^{"title" : ~title, "body" : ~lines}))
@(end)
@(do (put-jsonl vec))

Это можно сделать с помощью Awk; макрос Awk в TXR Lisp:

$ txr data.tl data
[{"title":"A random Title 1","body":"1- a block of text that can contain any character\nand it  also can contain multiple lines"},
 {"title":"A random Title 2","body":"2- a block of text that can contain any character\nand it  also can contain multiple lines"},
 {"title":"A random Title 3","body":"3- a block of text that can contain any character\nand it  also can contain multiple lines"}]

Код:

(awk
  (:set rs "\n\n" fs "\n")
  (:let (vec (vec)))
  ((and (equal [f 1] "BLOCK")
        (equal [f -1] "BLOCK"))
   (vec-push vec #J^{"title":~[f 0], "body":~(cat-str [f 2..-1])})
   (next))
  (t (error "bad data"))
  (:end (put-jsonl vec)))

Блок (:set...)предназначен для инициализации, и мы используем его для настройки разделителя записей rsи разделителя полей fs, которые аналогичны исходному Awk RSи FS. С разделителем полей, который является новой строкой, и разделителем записи, который является двойной новой строкой, мы получаем каждый информационный блок как запись, чьи поля выглядят следующим образом:

"title" "BLOCK" "body1" "body2"... "bodyn" "BLOCK"

В макросе awk поля доступны в виде списка с именем f.

Основной логикой является пара (условное действие ). Условие:

(and (equal [f 1] "BLOCK") (equal [f -1] "BLOCK"))

, что верно, если второй элемент fи последний элемент являются строкой "BLOCK". Если это так, выполняется действие, которое извлекает части и добавляет элемент в vecс помощью квазицитата JSON, как в первой программе. Мы также выполняем (next), чтобы перейти к следующей записи, чтобы избежать попадания в следующую пару действий условия -.

Пара действий следующего условия -, (t (error...))всегда выполняется, поскольку tистинно, и вызывает исключение.

Печатаем JSON в блоке (:end..),что похоже на END {... }в классическом Awk.

Говоря о проверке ошибок, первая программа до некоторой степени допускает неверные данные; есть способы тонкой настройки, чтобы отклонить неверные входные данные. Например, между записями может быть мусор, который молча пропускается, и если последний закрывающий БЛОК отсутствует, это нормально.

2
28.07.2021, 11:23

Использование любого awk в любой оболочке на каждом компьютере Unix:

$ cat tst.awk
BEGIN {
    RS = ""
    FS = "\n"
    printf "["
}
{
    gsub(/"/,"\\\\&")

    title = $1
    body  = $3
    for (i=4; i<NF; i++) {
        body = body "\\n" $i
    }

    print  (NR>1 ? "," : "")
    print  "    {"
    printf "        \"title\": \"%s\",\n", title
    printf "        \"body\": \"%s\"\n",   body
    printf "    }"
}
END {
    print "\n]"
}

$ awk -f tst.awk file
[
    {
        "title": "A random Title 1",
        "body": "1- a block of text that can contain any character\nand it  also can contain multiple lines"
    },
    {
        "title": "A random Title 2",
        "body": "2- a block of text that can contain any character\nand it  also can contain multiple lines"
    },
    {
        "title": "A random Title 3",
        "body": "3- a block of text that can contain any character\nand it  also can contain multiple lines"
    }
]
1
28.07.2021, 11:23

Можешь попробовать Миллер

$ mlr --inidx --irs '\n\n' --ifs 'BLOCK' --ojson --jvstack --jlistwrap \
    put -S 'for(k,v in $*){$[k] = strip(v)}' then \
    cut -f 1,2 then \
    rename '1,title,2,body' file
[
{
  "title": "A random Title 1",
  "body": "1- a block of text that can contain any character\nand it  also can contain multiple lines"
}
,{
  "title": "A random Title 2",
  "body": "2- a block of text that can contain any character\nand it  also can contain multiple lines"
}
,{
  "title": "A random Title 3",
  "body": "3- a block of text that can contain any character\nand it  also can contain multiple lines"
}
]

Вы можете предварительно настроить вывод, направив его черезjq '.'-или опустить опции --jvstack --jlistwrapи передать через jq -s '.':

.
$ mlr --inidx --irs '\n\n' --ifs 'BLOCK' --ojson \
    put -S 'for(k,v in $*){$[k] = strip(v)}' then \
    cut -f 1,2 then 
    rename '1,title,2,body' file | jq -s '.'
[
  {
    "title": "A random Title 1",
    "body": "1- a block of text that can contain any character\nand it  also can contain multiple lines"
  },
  {
    "title": "A random Title 2",
    "body": "2- a block of text that can contain any character\nand it  also can contain multiple lines"
  },
  {
    "title": "A random Title 3",
    "body": "3- a block of text that can contain any character\nand it  also can contain multiple lines"
  }
]

cut -f 1,2необходим только потому, что второй маркер BLOCKподразумевает третье (пустое )поле -его можно заменить глаголом remove-empty-columns, если вы предпочитаете (, хотя последнее не -потоковое ).


Работа со смежными новыми строками в теле

К сожалению, приведенное выше не делает различия между смежными символами новой строки в качестве разделителя входных записей и смежными символами новой строки, которые могут встречаться между BLOCK... BLOCKразделителями тела. В качестве обходного пути вы можете предварительно -обработать ввод, чтобы заменить новые строки в теле последовательностями \n, а затем заменить их буквальными новыми строками перед записью JSON (, где они будут экранированы обратно в \nс помощью Миллер):

sed '/^BLOCK/{:a;N;/BLOCK$/!ba;s/\n/\\n/g;}' file | 
  mlr --inidx --irs '\n\n' --ifs 'BLOCK' --ojson put -S '$2 = gsub($2,"\\n","\n"); for(k,v in $*){$[k] = strip(v)}' then cut -f 1,2 then rename '1,title,2,body'

Вы можете передать фильтр sed Миллеру как команду --prepipe, но цитирование становится затруднительным.

2
28.07.2021, 11:23

Мы можем использовать модуль Data ::Dumper для получения вывода json.

perl -MData::Dumper -00ne '
  my($title, $body) = 
    /^(.*?)\nBLOCK\n(.*)\nBLOCK\n$/s;

  push @A, {
    title => $title,
    body => $body,
  };

  END {
    $Data::Dumper::Useqq = 1;
    $Data::Dumper::Pair  = ": ";
    print Dumper \@A;
  }
' file | sed -Ee '1s/.{8}//;s/^ {8}//;$s/;$//'

Выход:

[
  {
    "body": "1- a block of text that can contain any character\nand it  also can contain multiple lines",
    "title": "A random Title 1"
  },
  {
    "title": "A random Title 2",
    "body": "2- a block of text that can contain any character\nand it  also can contain multiple lines"
  },
  {
    "body": "3- a block of text that can contain any character\nand it  also can contain multiple lines",
    "title": "A random Title 3"
  }
]
1
28.07.2021, 11:23

Python вместе с модулем itertoolsдля группировки входных данных в куски/абзацы, а затем их печати в стиле json с использованием модуля jsonс методом дампов.

python3 -c 'import sys, json, itertools
ifile,rs = sys.argv[1],chr(10)

lod = []
with open(ifile) as fh:
  for k,g in itertools.groupby(fh, lambda x: x == rs):
    if not k:
      para = list(g)
      title,x,*body = list(map(lambda x: x.rstrip(rs),para[0:-1]))
      lod.append({
        "title": title,
        "body": rs.join(body)
      })

print(json.dumps(lod, sort_keys=False, indent=4))
' file

Выход:

[
    {
        "title": "A random Title 1",
        "body": "1- a block of text that can contain any character\nand it  also can contain multiple lines"
    },
    {
        "title": "A random Title 2",
        "body": "2- a block of text that can contain any character\nand it  also can contain multiple lines"
    },
    {
        "title": "A random Title 3",
        "body": "3- a block of text that can contain any character\nand it  also can contain multiple lines"
    }
]
1
28.07.2021, 11:23

Теги

Похожие вопросы