Парсинг файла с помощью инструментов обработки текста

Файл похож:

1140.271257 0.002288454025 0.002763420728 0.004142512599 0 0 0 0 0 0 0 0 0 0 0 
1479.704769 0.00146621631 0.003190634646 0.003672029231 0 0 0 0 0 0 0 0 0 0 0 
1663.276205 0.003379552854 0.04643209167 0.0539399155 0 0 0 0 0 0 0 0 0 0 0 0 

Могу я использовать некоторый инструмент обработки текста для разделения его на два файла, такие как:

1:

1140.271257 0.002288454025 0.002763420728 0.00414251259
1479.704769 0.00146621631 0.003190634646 0.003672029231
1663.276205 0.003379552854 0.04643209167 0.0539399155

2:

0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 

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

5
задан 9 September 2015 в 04:18

6 ответов

С awk. Команда ниже проверяет каждую запись в каждую строку и записи в различных файлах в моем примере out1 и out2. Если будет новая строка во входном файле, то также новая строка будет записана в выходном файле.

awk '{for(i=1;i<=NF;i++) {if($i!=0) {printf "%s ",$i > "out1"} else {printf "%s ",$i > "out2"}; if (i==NF) {printf "\n" > "out1"; printf "\n" > "out2"} }}' foo
<час>

Пример

входной файл

cat foo

1140.271257 0.002288454025 0.002763420728 0.004142512599 0 0 0 0 0 0 0 0 0 0 0 
1479.704769 0.00146621631 0.003190634646 0.003672029231 0 0 0 0 0 0 0 0 0 0 0 
1663.276205 0.003379552854 0.04643209167 0.0539399155 0 0 0 0 0 0 0 0 0 0 0 0

команда

awk '{for(i=1;i<=NF;i++) {if($i!=0) {printf "%s ",$i > "out1"} else {printf "%s ",$i > "out2"}; if (i==NF) {printf "\n" > "out1"; printf "\n" > "out2"} }}' foo

выходные файлы

cat out1

1140.271257 0.002288454025 0.002763420728 0.004142512599 
1479.704769 0.00146621631 0.003190634646 0.003672029231 
1663.276205 0.003379552854 0.04643209167 0.0539399155 

cat out2

0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0
6
ответ дан 23 November 2019 в 08:42

Просто получите первые числа, которые не равны 0, а затем просто поместите остальные в другой файл

В этом случае вы можете использовать grep с Perl Compatible Regex ( -P):

  • Чтобы получить первые числа, отличные от нуля:

    $ grep -Po '^.*\s\d+\.\d+(?=\s0\s.*)' file.txt 
    1140.271257 0.002288454025 0.002763420728 0.004142512599
    1479.704769 0.00146621631 0.003190634646 0.003672029231
    1663.276205 0.003379552854 0.04643209167 0.0539399155
    
    • ^.*\s\d+\.\d+ получит желаемую часть

    • (?=\s0\s.*) является положительным прогнозным шаблоном нулевой ширины, гарантирующим, что у нас есть старт нулей после нашего желаемого положения

    Чтобы сохранить его как filex1.txt:

    grep -Po '^.*\s\d+\.\d+(?=\s0\s.*)' file.txt >filex1.txt
    
  • Чтобы получить остальные, то есть нули:

    $ grep -Po '\s\d+\.\d+\s\K0\s.*' file.txt 
    0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0
    
    • \s\d+\.\d+\s убедитесь, что мы имеем ненулевая запись до нашей желаемой части, \K отбрасывает совпадение

    • 0\s.* получит нам желаемую часть, то есть нулевые записи, начиная с первой

      [ 1135]

    Чтобы сохранить его как filex2.txt:

    grep -Po '\s\d+\.\d+\s\K0\s.*' file.txt >filex2.txt
    
2
ответ дан 23 November 2019 в 08:42

Вы действительно можете использовать инструмент для обработки текста, но если цель состоит в том, чтобы отделить первые 4 поля от того, что следует за ними, используя cut, то достаточно:

 cut -d ' ' -f 1-4 infile > outfile1
 cut -d ' ' -f 5- infile > outfile2
user@debian ~/tmp % cat infile
1140.271257 0.002288454025 0.002763420728 0.004142512599 0 0 0 0 0 0 0 0 0 0 0 
1479.704769 0.00146621631 0.003190634646 0.003672029231 0 0 0 0 0 0 0 0 0 0 0 
1663.276205 0.003379552854 0.04643209167 0.0539399155 0 0 0 0 0 0 0 0 0 0 0 0 
user@debian ~/tmp % cut -d ' ' -f 1-4 infile
1140.271257 0.002288454025 0.002763420728 0.004142512599
1479.704769 0.00146621631 0.003190634646 0.003672029231
1663.276205 0.003379552854 0.04643209167 0.0539399155
user@debian ~/tmp % cut -d ' ' -f 5- infile 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 
3
ответ дан 23 November 2019 в 08:42

Принятие, после того как Вы добираетесь 0 вся остальная часть полей, похоже на это, можно сказать:

awk -v FS=" 0 " '{print $1 > "f1"; gsub($1 " ",""); print > "f2"}' file

Это устанавливает разделителя полей на строку 0 и печатает первое поле (то есть, до первого 0) в файл f1. Затем это удаляет это первое поле из исходной строки и печатает ее результат в файл f2.

0
ответ дан 23 November 2019 в 08:42

Я рекомендовал бы использовать жемчуг для этого. сохраните свой вход в input.txt и выполненный следующая команда:

cat input.txt | perl -ane 'foreach(@F){   #loop through input and split each line into an array
  chomp; #remove trailing newline
  if($_ == 0){   #print the element to STDOUT if it is "0"
    print $_," "
  }
  else{     #print the element to STDERR if it is not "0"
    print STDERR $_," "
    }
  };
  print "\n"; print STDERR "\n";' #add a newline at the end 
> x2.txt 2> x1.txt    #redirect STDOUT to x2.txt and STDERR to x1.txt

здесь как острота для копирования вставки:

cat input.txt | perl -ane 'foreach(@F){chomp;if($_ == 0){print $_," "}else{print STDERR $_," "}};print "\n"; print STDERR "\n";' > x2.txt 2> 1.txt
2
ответ дан 23 November 2019 в 08:42

Другой подход с помощью Perl:

perl -lne '/(.*?)\s(0\s.*)/; print "$1"; print STDERR "$2"' file > filex1 2> filex2

Регулярное выражение будет соответствовать всему до 1-го 0 окруженный пробелом и затем всем от того 0 в конец строки. Круглые скобки получают те две группы как $1 и $2 соответственно. -l включает автоматическое запаздывающее удаление новой строки (chomp) и добавляет a \n каждому print звонить. Так, мы печатаем $1 к стандартному выводу и $2 к стандартной погрешности и затем перенаправляют каждого в различный файл.

Так как это - Perl, существует больше чем один способ сделать это. Это - та же идея как ответ Wayne_Yux, но упрощенный:

perl -lane '@A=grep{$_==0}@F; @B=grep{$_!=0}@F;print STDERR "@A"; print "@B"' file > filex1 2>filex2

С другой стороны, более простое grep -P:

grep -oP '^.+?(?=\s0\s)' file > filex1
grep -oP ' \K0 .*' file > filex2
2
ответ дан 23 November 2019 в 08:42

Другие вопросы по тегам:

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