Фильтрация набора данных CSV для поиска строк и сохранения их в текстовом файле

Вы можете сделать это с помощью awk,чей match(), который устанавливает переменные RSTARTи RLENGTH, весьма полезен для этого:

<mySequence.fasta awk -v C=N '{
  i=0
  while (match($0, C "+")) {
    printf "Position %d %s %d\n", i+RSTART, C, RLENGTH
    i += RSTART+RLENGTH-1
    $0 = substr($0, RSTART+RLENGTH)
  }}'

Или с помощью perlс использованием массивов @-и @+, записывающих начало и конец совпадений:

perl -ne 'printf "Position %d N %d\n", $-[0]+1, $+[0]-$-[0] while /N+/g'

Еще один немного более быстрый (по крайней мере, с моей версиейperl)perlподхода с использованием(экспериментального)(?{...})оператора регулярного выражения:

perl -ne '0 while /N(?{$s=pos})N*(?{printf "Position %d N %s\n", $s, pos()-$s+1})/g'
2
20.10.2019, 15:45
5 ответов

Я недостаточно использую сценарии оболочки, но часто делаю подобные вещи на других языках. Я дам кое-что, чтобы помочь вам организовать ваши поиски.

1 -Вам нужно проанализировать CSV-файл

Вы можете посмотреть, как анализировать CSV-файл по этой ссылке :https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash

2 -Вам нужно получить строки, совпадающие со словом «прочитано»

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

/\b(\w*read\w*)\b/g

Поместите его на этот сайт, чтобы получить информацию о выражении:https://regexr.com/

3 -Вам необходимо отсортировать вывод по критерию

Для этого можно использовать команду sort . Это проще, чем присваивать массиву и сортировать этот массив.

4 -Перенаправление выхода

Вы можете легко перенаправить вывод оболочки в файл с помощью чего-то вроде «script.sh > my _output.txt». Или сделайте это внутри вашего скрипта 'var > output.txt'

0
27.01.2020, 22:08

Учусь awk, поэтому жду отзывов от мудрецов:

cat file | tr -s ' ' | awk -F, 'BEGIN { print "Score ID" } tolower($4) ~ /read/ { if($5 >= 20) print $5,$9 }' > output

В этом случае, чтобы иметь возможность использовать формат OP, замените все пробелы только одним

tr -s ' '

Использовать запятую в качестве разделителя:

-F,

Чтобы сделать сравнение нечувствительным к регистру:

tolower($4)

В четвертом столбце есть строка "прочитано"

tolower($4) ~ /read/

Если значение пятого столбца равно или больше 20, выведите:

if($5>=20) print $5,$9

Добавить заголовок (Сейчас пытаюсь сделать это с помощьюawk)

 BEGIN { print "Score ID" }

Выход

score ID
 24  1
 39  2
1
27.01.2020, 22:08

Если вы хотите "использовать команды оболочки",классическим решением будет конвейер с grep, cut и sort. Некоторые заметки о необходимых шагах (Я частично протестировал):

Во-первых, вы cutсокращаете число столбцов/полей до трех необходимых.

С помощью grepвы выполняете "анализ". Это «читается» только как целое слово? деликатный случай? Значение оценки можно довольно легко проверить в том же регулярном выражении (после вырезания ). Что-то вроде:

grep  "\<[Rr]ead\>.*,.*[2-9][0-9].*,"

Это работает, но вы можете видеть пределы этого "простого" подхода. Оценка «-20» будет считаться «выше 20» (, поскольку она имеет «абсолютное значение 20 или выше», так сказать )

.

С помощью sortвы... сортируете оставшиеся строки, используя на этот раз реальное числовое значение. Это делает команду (pipe )похожей на:

cut OPT FILE | grep "regex" | cut OPT2 | sort OPT >report.txt

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

0
27.01.2020, 22:08

с использованием Миллера(https://github.com/johnkerl/miller)и начиная с

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2
m,n,o,Have you read this book?,15,g,h,i,3

и работает

mlr --csv filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv >output.csv

у вас будет

score,ID
24,1
39,2

Некоторые подробности о команде:

  • --csv, чтобы установить формат ввода и вывода
  • filter -S '$message=~"(r|R)ead" && $score>20', чтобы применить фильтр
  • cut -f score,IDдля выбора полей

Если у вас неверный CSV-файл, в котором ячеек больше, чем столбцов заголовков, например

D,E,F,message,score,A,B,C,ID
d,e,f,Let's read a book,24,a,b,c,1
j,k,l,Read this book,39,d,e,f,2,a wrong cell,another wrong cell
m,n,o,Have you read this book?,15,g,h,i,3

вы можете применить опцию raggedи запустить

mlr --csv --ragged unsparsify then filter -S '$message=~"(r|R)ead" && $score>20' then cut -f score,ID input.csv>output.csv

Однако, если у вас возникли проблемы с файлом CSV, лучше всего опубликовать его здесь целиком

2
27.01.2020, 22:08

Немного awk, немного регулярного выражения и убираем пробелы, перенаправляя их кcolumn

awk -F',' '{if ( $4 ~ /[Rr]ead/ &&  $5 > 20 || NR==1) print $5, $9}' data.csv | column -t

Объяснение.... после установки разделителя полей на a с помощью-F','

....если 4-е поле соответствует регулярному выражению ~с «Читать» или «прочитано» и &&5-е поле > 20 или ||мы находимся в первой строке (с заголовки )NR==1, затем распечатайте интересующие вас столбцы......

Просто так

Если вы знаете заголовки столбцов, но ленитесь считать....

Загрузить заголовки в ассоциативный массив

declare -A HEADS=( [mess]=mess [id]=ID [score]=score )

..... awkвывести индексы столбцов из первой строки файла данных в массив

for j in "${!HEADS[@]}"; do HEADS[$j]=$(awk -F',' -v s=${HEADS[$j]} 'NR==1 {for (i=1; i<=NF; ++i) { if ($i ~ s ) print i }}' data.csv) ; done

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

awk -v mess=${HEADS[mess]} -v score=${HEADS[score]} -v id=${HEADS[id]} -F',' '{if ( $mess ~ /[Rr]ead/ &&  $score >20 || NR==1) print $score, $id}' data.csv | column -t
0
27.01.2020, 22:08

Теги

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