2017-02-11 13 views
1

Я пытаюсь объединить все числа, которые находятся в научной нотации из файла в одну строку. ввода (test_sc.txt)Номера для печати, которые находятся в научной нотации

A B C 1e+03 1e-03 3.39e+03 
G H february 
E 2.834967e+02 798 
j 0.000000e+00 

Желаемый результат:

1e+03 1e-03 3.39e+03 2.834967e+02 0.000000e+00 

Текущая команда AWK:

awk 'BEGIN {k=""}; {for (i=1; i<=NF; i++) {if ($i ~ (/e-/ || /e\+/)) {k=k$i" ";}}}; END {print k}' "test_sc.txt" 

Токовый выход:

1e+03 1e-03 

Хорошо, если я поменяю шаблон до /e/ это работает, но печатает february тоже.

если я добавляю print $i в команду awk, все номера печатаются правильно. Однако, как я понимаю, awk изменяет обозначения внутри при работе с числами. Как это остановить?

gawk 4.0 (Linux), something similar is described here,, но они не объясняют поведение и рекомендовал изменить awk

Кажется, задача решается проще при работе со строками, а не числами. Я попробую sed, если это осложняется awk.

ответ

1

Рассмотрим следующий подход: переборе всех полей и проверить, если поле матчи конкретных регулярных выражений шаблон для чисел в научной нотации/([0-9]+\.)?[0-9]+e[+-][0-9]+/

awk '{for(i=1;i<=NF;i++){ if($i~/^([0-9]+\.)?[0-9]+e[+-][0-9]+$/){ print $i} }}' test_sc.txt 

Выход:

1e+03 
1e-03 
3.39e+03 
2.834967e+02 
0.000000e+00 
0

Что-то не так с двумя шаблонами в одной паре круглых скобок.Это работает:

awk 'BEGIN {k=""}; {for (i=1; i<=NF; i++) {if (($i ~ /e-/) || ($i ~ /e\+/)) {k=k$i" ";}}}; END {print k}' "test_sc.txt" 

Улучшение, как предложенный @iiSeymour в комментарии:

awk '{for (i=1;i<=NF;i++) if ($i~/e[-+]/){k=(k?k OFS $i:$i)}}END{print k}' 
+1

Вы можете избежать логические ИЛИ и двойного матча регулярного выражения, используя класс символов '[+ -]' и сделать использование тернарного оператора исключает конечное пространство 'awk '{для (i = 1; i <= NF; i ++), если ($ i ~/e [- +] /) {k = (k? k OFS $ i: $ i)}} END {print k} '' –

+1

Это может показаться, что многие строки были числами в научной нотации, когда они не являются. Вашему регулярному выражению потребуется много работы, вместо этого посмотрите на другие ответы. –

1

Вы можете использовать -o вариант grep для этого тогда трубы в xargs, чтобы получить все результаты на одной строке :

$ grep -Eo '\S+e[-+]\S+' file | xargs 
1e+03 1e-03 3.39e+03 2.834967e+02 0.000000e+00 
+0

Спасибо, это хорошо! –

+1

'echo 'me + you' | grep -Eo '\ S + e [- +] \ S +' 'выводит' me + you'. Ваше регулярное выражение должно быть более строгим, чтобы избежать ложных совпадений. –

+1

@ EdMorton, действительно, OP может сжимать соответствующие ограничения по мере необходимости, я только хотел передать использование 'grep -o' и' xargs' для этой проблемы. –

0

Вы можете использовать AWK, чтобы проверить, если поле может быть преобразовано в число, а затем просто проверить e или E в поле:

$ awk '{ for (i=1;i<=NF;i++) if ($i+0==$i && $i ~ /e|E/) s=s $i FS} 
     END { if (s) print s }' /tmp/file 
1e+03 1e-03 3.39e+03 2.834967e+02 0.000000e+00 

или, чтобы избежать конца блока:

$ awk -v ORS=' ' '{ for (i=1;i<=NF;i++) if ($i+0==$i && $i ~ /e|E/) print $i}' /tmp/file 
1e+03 1e-03 3.39e+03 2.834967e+02 0.000000e+00 
1

С GNU AWK для мульти-гольцов RS, и если вы не заботитесь о пустой полукокса в конце и не символ новой строки:

$ awk -v RS='\\s' -v ORS=' ' '$0==($0+0) && /e/' file 
1e+03 1e-03 3.39e+03 2.834967e+02 0.000000e+00 

выше только тесты, если каждое значение является число (т.е. он равен себе плюс ноль) и содержит e, и если это так печатает. Если вы хотите удалить концевой пустой символ и добавить символ новой строки вы можете массировать до:

$ awk -v RS='\\s' '$0==($0+0) && /e/{s = (s=="" ? "" : s OFS) $0} END{print s}' file 
1e+03 1e-03 3.39e+03 2.834967e+02 0.000000e+00 
+1

'0.100e100' является законной строкой IEEE с плавающей запятой. он нормализуется до «1e99» (попробуйте в Perl, Python, что-нибудь еще, использующее базовый 'atof' – dawg