Как разобрать строку, в которой число после определенной строки превышает пороговое значение?

У меня есть файл (list_20.txt), который выглядит так:

[{"d_prime":"0.475425","variation1":"rs909776","r2":"0.057940","variation2":"rs16991816","population_name":"1000GENOMES:phase_3:KHV"}]
[{"r2":"0.057940","variation1":"rs909776","d_prime":"0.475425","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs16991819"}]
[{"variation1":"rs909776","r2":"0.078476","d_prime":"0.546491","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs8114269"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs8114269","r2":"0.073418","variation1":"rs6130034","d_prime":"0.528588"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs1201686","r2":"0.060239","variation1":"rs3746539","d_prime":"0.271891"}]
[{"variation2":"rs1201686","population_name":"1000GENOMES:phase_3:KHV","d_prime":"0.280262","r2":"0.058212","variation1":"rs2144011"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs10485662","r2":"0.058826","variation1":"rs844808","d_prime":"0.423639"}]
[{"variation2":"rs6065565","population_name":"1000GENOMES:phase_3:KHV","d_prime":"0.638509","r2":"0.110749","variation1":"rs6139746"}]
[{"r2":"0.110749","variation1":"rs6139746","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072936"}]
[{"population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6065562","variation1":"rs6139746","r2":"0.091021","d_prime":"0.606214"}]
[{"variation1":"rs6139746","r2":"0.910749","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072937"}]
...

Я хотел бы для извлечения только строк, которые имеют значение после "r2":" больше 0,7 и меньше или равно 1

в этом примере ожидаемым результатом будет только эта строка:

[{"variation1":"rs6139746","r2":"0.910749","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072937"}]

Я пробовал это:

awk '$NF >= 0.8 && $NF <1 {print $0}' list_20.txt  > 20.out

, но я получил пустой файл. Также эта команда не относится к интересующей строке: "r2":"

0
23.06.2020, 18:01
5 ответов
awk -F'[][{},]' '{
  for (i=3;i<=NF-2;i++){
    if ($i ~ /^"r2"/){
      r2=substr($i, 7, length($i)-7)
      if (r2>0.7 && r2<=1){ print; break }
    }
  }
}' list_20.txt > 20.out

Используйте ], [, {, }и ,в качестве разделителей полей. Затем перебираем поля в каждой записи, пропуская первые два и последние два поля (, так как они всегда пусты ).

Проверить, начинается ли текущее поле с "r2", и извлечь значение с помощью substr($i, 7, length($i)-7), т. е. пропустить первые 6 символов "r2":"и опустить последний символ ".

Распечатать запись, если значение находится в пределах диапазона, и разорвать цикл.

0
18.03.2021, 23:25

Неэффективный метод, но моя попытка

sed 's/[\["{}]//g' i.txt| sed 's/\]//g'|sed 's/,/ /g'| awk -F ":" '{for(i=1;i<=NF;i++){if ($i ~ /r2/ && $(i+1) > 0.7) {print $0}}}'| perl -pne "s/ /\n/g"| sed 's/^/"/g'|sed 's/$/"/g'| perl -pne 's/\n/,/g'| sed 's/^/[{/g'| sed 's/$/}]/g'| sed "s/,}]/}]/g"

выход

[{"variation1:rs6139746","r2:0.910749","d_prime:0.638509","population_name:1000GENOMES:phase_3:KHV","variation2:rs6072937"}]
0
18.03.2021, 23:25

Поскольку это похоже на JSON,давайте воспользуемся парсером JSON командной строки:

$ jq '.[] | select((.r2|tonumber) > 0.7 and (.r2|tonumber) <= 1)' file
{
  "variation1": "rs6139746",
  "r2": "0.910749",
  "d_prime": "0.638509",
  "population_name": "1000GENOMES:phase_3:KHV",
  "variation2": "rs6072937"
}

Нам нужно преобразовать значения ключей r2в правильные числа из строк с tonumber, но кроме этого, это простой фильтр через select().

Мы можем несколько сократить его или, по крайней мере, не преобразовывать каждое число дважды с помощью

jq '.[] | (.r2|tonumber) as $r2 | select($r2 > 0.7 and $r2 <= 1)' file

Если вы хотите, чтобы результаты были в том же формате, что и ввод, используйте

$ jq -c '.[] | (.r2|tonumber) as $r2 | select($r2 > 0.7 and $r2 <= 1) | [.]' file
[{"variation1":"rs6139746","r2":"0.910749","d_prime":"0.638509","population_name":"1000GENOMES:phase_3:KHV","variation2":"rs6072937"}]

То есть запросите «компактный вывод» с помощью -cи создайте массив для каждого результата, извлеченного с помощью фильтра select()с помощью [.].

4
18.03.2021, 23:25

С Awk:

awk 'match($0, /"r2":"[^"]+"/) {
  t = substr($0, RSTART+6, RLENGTH-7)
  f = 0.7<t+0 && t+0<=1
  if ( f ) print 
}' list_20.txt 

Это можно сделать и в perl:

perl -lne '
  print if /"r2":"(.*?)"/ and 0.7<$1 && $1<=1;
' list_20.txt

Ищем строку r2 в кавычках и то, что следует за ней. Затем применяется условие проверки диапазона, а затем печатается строка, если она находится в пределах диапазона.

1
18.03.2021, 23:25

При условии, что числа являются числами с плавающей запятой, вы можете выделить строки следующим образом:

$  LC_ALL=C grep -E '"r2":"((0?\.(7[0-9]*[1-9][0-9]*|[89][0-9]*))|1(\.0*)?)"' list_20.txt 

-Eопция включает расширенное регулярное выражение

0
18.03.2021, 23:25

Теги

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