Преобразуйте файл "таблица-данные" в CSV - PullRequest
0 голосов
/ 11 декабря 2018

У меня есть длинный текстовый файл с некоторыми «табличными» данными, например:

12/10/2018  aaaa bbb     xxxxxxxxxxxxxxxxxxxxxxxxxxxxx      002424004234
                         xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                         xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                         xxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
12/11/2018 cccc        dddd     yyyyyyyyyyyyyyyyyyyyyy      0542121212122
                                yyyyyyyyyyyyyyyyyyyyyy
12/12/2018 eeee       ffffff   zzzzzzzzzzzzzzzzzzzzzzz      0639872651252
12/13/2018  ggggggg hhhhhh     vvvvv vvvvvvvvvvvvvvvvv      1968745213648
                               vvvvvvvvvvvvvvvvvvvvvvv
12/14/2018  ....

в результате сканирования, где некоторые столбцы похожи на «ячейки» электронной таблицы.Как я могу с помощью некоторых инструментов командной строки преобразовать файл CSV, например:

12/10/2018,aaaaaaaa,bbbbb,xxxxxx.......xxxx,002424004234
12/11/2018,ccccccc,dddddd,yyyyyy.......yyyy,0542121212122

и т. Д.?

Спасибо

РЕДАКТИРОВАТЬ: У меня есть текстовый файл в результате сканирования документов.Эти документы представляют данные в «табличной форме», т. Е. Третий столбец представляет собой «многострочный» текст.Я бы преобразовал это в простой файл CSV, т. Е. В ОДНОЙ строке я бы весь текст многострочного "ячейки".xxxxx ... xxxx воспроизводит многострочный текст третьего столбца

EDIT2: Пример данных

Date         AMOUNT      OP     DESCRIPTION                                 CODE
12/10/2018   $123,45    id01   payment for hotel in Las Vegas            005214875462     
                              room
                              room service
                              dinner
                              golf club

12/11/2018   $400,00    id04    cash from ATM                            0528158852687
                                 located in L.A.
12/12/2018   $1000,00   id99    ACME tornado pill                         854674852658

Я хотел бы преобразовать в

12/10/2018;$123,45;id01;payment for hotel in Las Vegas room room service     dinner golf club;005214875462     
12/11/2018;$400,00;id04;cash from ATM located in L.A.;0528158852687
12/12/2018;$1000,00;id99;ACME tornado pill;854674852658

Ответы [ 5 ]

0 голосов
/ 12 декабря 2018
$ cat tst.awk
BEGIN { OFS = ";" }
(NR==1) || !NF { next }
/^[[:space:]]/ {
    gsub(/^[[:space:]]+|[[:space:]]+$/,"")
    desc = desc " " $0
    next
}
NR > 2 { print bef, desc, aft }
{
    bef = $1 OFS $2 OFS $3
    aft = $NF
    gsub(/^([^[:space:]]+[[:space:]]+){3}|[[:space:]]+[^[:space:]]+[[:space:]]*$/,"")
    desc = $0
}
END { print bef, desc, aft }

$ awk -f tst.awk file
12/10/2018;$123,45;id01;payment for hotel in Las Vegas room room service dinner golf club;005214875462
12/11/2018;$400,00;id04;cash from ATM located in L.A.;0528158852687
12/12/2018;$1000,00;id99;ACME tornado pill;854674852658

Приведенное выше сохранит пробел в описании, если это имеет значение.

0 голосов
/ 12 декабря 2018

Использование Perl с одной строкой

> cat tomc_in.dat
Date    AMOUNT  OP  DESCRIPTION CODE
12/10/2018  $123,45 id01    payment for hotel in Las Vegas  005214875462
                              room
                              room service
                              dinner
                              golf club
12/11/2018  $400,00 id04    cash from ATM   0528158852687
                                 located in L.A.
12/12/2018  $1000,00    id99    ACME tornado pill   854674852658
> perl -F"/\s+/" -lane ' print $all if $idp and /^\d+/ and $idp ne $F[2] ;if($.>1) { if(/^\d+/) { $p="$F[0];$F[1];$F[2]";$c=$F[-1];$de=join(" ",@F[3..$#F-1]);$idp=$F[2]} else {s/^\s*|\s*$//g;$de.=" ".$_}; $all="$p;$de;$c"; } END { print $all } ' tomc_in.dat
12/10/2018;$123,45;id01;payment for hotel in Las Vegas room room service dinner golf club;005214875462
12/11/2018;$400,00;id04;cash from ATM located in L.A.;0528158852687
12/12/2018;$1000,00;id99;ACME tornado pill;854674852658
>
0 голосов
/ 12 декабря 2018

ВХОД:

$ cat input.dat
Date         AMOUNT      OP     DESCRIPTION                                 CODE
12/10/2018   $123,45    id01   payment for hotel in Las Vegas            005214875462     
                              room
                              room service
                              dinner
                              golf club

12/11/2018   $400,00    id04    cash from ATM                            0528158852687
                                 located in L.A.
12/12/2018   $1000,00   id99    ACME tornado pill                         854674852658

Команда:

$ awk 'BEGIN{OFS=";"}/^[0-9]{2}\/[0-9]{2}\/[0-9]{4}/{if(NR>2){print date,amount,desc, op}date=$1; amount=$2; op=$3; code=$NF; for(i=4;i<=NF-1;i++){if(i==4){desc=$i}else{desc=desc" "$i}};next}{for(i=1;i<=NF;i++){desc=desc" "$i}}END{print date,amount,desc, op}' input.dat

Выход:

Date;AMOUNT;OP;DESCRIPTION;CODE
12/10/2018;$123,45;payment for hotel in Las Vegas room room service dinner golf club;id01
12/11/2018;$400,00;cash from ATM located in L.A.;id04
12/12/2018;$1000,00;ACME tornado pill;id99

Пояснения:

  • BEGIN{OFS=";"; print "Date;AMOUNT;OP;DESCRIPTION;CODE"} установите разделитель выходного поля на ; и напечатайте строку заголовка
  • /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}/ для идентификациистроки, начинающиеся с даты
  • {if(NR>2){print date,amount,desc, op}, если мы не находимся в настоящее время на первой строке данных, мы печатаем содержимое переменной, которую вы использовали для преобразования данных
  • date=$1; amount=$2; op=$3; code=$NF; for(i=4;i<=NF-1;i++){if(i==4){desc=$i}else{desc=desc" "$i}};nextСохраните поля входных данных в переменных и сгенерируйте переменную desc, добавив все поля до поля, предшествующего коду, и перейдите к следующей строке
  • Когда мы достигнем строки, которая не начинается с даты, {for(i=1;i<=NF;i++){desc=desc" "$i}}добавить все к описанию
  • END{print date,amount,desc, op} напечатать последнюю строку

    # gawk profile, created Wed Dec 12 17:34:39 2018
    # BEGIN rule(s)
    
    BEGIN {
           OFS = ";"
           print "Date;AMOUNT;OP;DESCRIPTION;CODE"
    }
    
    # Rule(s)
    
    /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}/ { 
           if (NR > 2) { 
                   print date, amount, desc, op
            }
           date = $1
           amount = $2
           op = $3
           code = $NF
           for (i = 4; i <= NF - 1; i++) {
                  if (i == 4) { 
                           desc = $i
                   } else {
                           desc = desc " " $i
                    }
            }
           next
    }
    
    {
          for (i = 1; i <= NF; i++) {
                  desc = desc " " $i
            }
    }
    
    # END rule(s)
    
    END {
           print date, amount, desc, op
    }
    
0 голосов
/ 12 декабря 2018

Я решил, что ваш входной файл разделен табуляцией
и что вы получаете запятые между описаниями в разных строках.
(потому что мне не нравилось видеть "... обслуживание номеров ...")

Ваш пример данных

cat input; 
Date    AMOUNT  OP  DESCRIPTION CODE
12/10/2018  $123,45 id01    payment for hotel in Las Vegas  005214875462
                              room
                              room service
                              dinner
                              golf club
12/11/2018  $400,00 id04    cash from ATM   0528158852687
                                 located in L.A.
12/12/2018  $1000,00    id99    ACME tornado pill   854674852658

Мой скрипт

cat collapse_column.awk
#! /usr/bin/awk -f
# collapse_column.awk

BEGIN{FS="\t"; OFS=";"; getline}
/^[0-9]/{
    if(Date){
        print Date,AMOUNT,OP,DESCRIPTION,CODE;
    }
    Date=$1;AMOUNT=$2;OP=$3;DESCRIPTION=$4;CODE=$5
}

/^[^0-9]/{
    gsub(/ [[:space:]]+/, ",")
    DESCRIPTION = DESCRIPTION $0
}
END{print Date,AMOUNT,OP,DESCRIPTION,CODE}

Результат

$ ./collapse_column.awk input 
12/10/2018;$123,45;id01;payment for hotel in Las Vegas,room,room service,dinner,golf club;005214875462
12/11/2018;$400,00;id04;cash from ATM,located in L.A.;0528158852687
12/12/2018;$1000,00;id99;ACME tornado pill;854674852658

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

0 голосов
/ 12 декабря 2018

Вы должны иметь несколько пробелов в качестве разделителя полей (FS) и обрезать конечные пробелы во входных данных.Проверьте следующий код (сохранить как ip.awk)

BEGIN{
    FS="[[:space:]][[:space:]]+";
    op[0] = "";
    line  = 0;
}
{
    if(NR <= 1 || NF == 0)
        skip;
    if(NF==5)
    {
        line = line + 1;
        op[line,"1"] = $1;
        op[line,"2"] = $2;
        op[line,"3"] = $3;
        op[line,"4"] = $4;
        op[line,"5"] = $5;
    }
    else{
        #printf("line:%d,tok=%s,ex=%s\n",line,$2,op[line,"4"]);
        op[line,"4"] = op[line,"4"] " " $2;
    }
}
END{
OFS=";"
for(i=1;i<=line;i++)
    print op[i,"1"],op[i,"2"],op[i,"3"],op[i,"4"],op[i,"5"];
}

Вы можете запустить код, подобный этому 1.txt - это входной файл

cat 1.txt | sed 's/[ \t]*$//g' | awk -f ip.awk

OP

1010 *
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...