2016-03-16 4 views
1

У меня есть большое количество больших файлов в форматеЗамена точности чисел с плавающей точкой в ​​существующий файл

step 80 
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
step 90 
1.54045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
1.16545e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
1.10045e+07 1.10125e+07 1.20345e+07 2.40225e+07 4.30245e+07 
... 

Числа различны (некоторые из них то же самое здесь из-за моей лени).

Я хочу изменить точность чисел с плавающей запятой. То есть, я хочу заменить предыдущий файл:

step 80 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
step 90 
1.54e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.16e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
... 

если желаемая точность составляет 2 цифры после десятичной точки.

Как я могу сделать это эффективным образом и использовать низкую память (т. Е. Мне не нужно загружать полный файл в память).

Предпочтительно решение с использованием сценария bash.

+0

Форматирование происходит так, потому что у вас есть вкладки. ;-) – DevSolar

+0

@DevSolar Вы правы! – becko

ответ

1

Вы можете использовать Perl для чтения файла строка за строчкой и переформатировать номера с sprintf():

perl -pe '!/^step/ && s/(\S+)/sprintf("%.2e", $1)/ge' file 
+1

Это прекрасно работает. Единственным недостатком является то, что 'sed' работает быстрее ... но сейчас он не работает отлично. – becko

+0

Как я могу назвать это внутри gnu parallel. Это не работает 'parallel --jobs 20 perl -ape '!/^ Step/&& s/(\ S +)/sprintf ("%. 1e ", $ 1)/ge' {}> {} .fixed ::: * ' – becko

+0

@becko возможно, задайте новый вопрос для решения этой проблемы. Кроме того, переключатель '-a' в' perl' может быть опущен (согласно редактированию). –

1

Как быстро & грязного раствора, если «длинные» части чисел являются единственными последовательностями длиной более 2-х цифр, в то время, в передней части 'e' ...

sed -i "s/\([0-9]\{2\}\)[0-9]*e/\1e/g" <filename> 
  • "s - - поиск
  • / - начать "поиск" термин
  • \( - начать группу
  • [0-9] - цифры
  • \{2\} - ... два из них (редактирования этого для различных выходных точностей)
  • \) - конец группы
  • [0-9]* - следовать любое количество цифр
  • e - затем 'e'
  • / - конец «поиск» термин, начинают «заменить» термин
  • \1 - содержимое первой группы (две первые цифры)
  • e - и 'e'
  • / - конец "заменить" термин
  • g - сделать любое количество раз в каждой строке ("глобальный")

В -i вариант (расширение GNU) делает замену in-file, поэтому лучше попробуйте его без -i, чтобы убедиться, что выход такой, как хотелось.

+0

@ LutzHorn: Очень важно. – DevSolar

+0

Ваше состояние не выполняется. «Шаг» может быть любым любым положительным целым числом, большим со многими цифрами или маленьким. – becko

+0

@becko Должно быть легко улучшить соответствие этого ответа. Теперь у вас есть хорошие решения, используйте их. –

1
$ sed 's/\(\...\)...e/\1e/g' < so.txt 

step 80 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
step 90 
1.54e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.16e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
1.10e+07 1.10e+07 1.20e+07 2.40e+07 4.30e+07 
+0

'...'? Это ново. Что оно делает? – DevSolar

+1

Точка '.' соответствует * любой * знак. Ваше решение безопаснее :) –

+0

Я думал, что три подряд были чем-то особенным. Да, соответствие любому перед 'e' ... нетерпеливо. :-D – DevSolar

0

С AWK вы можете сделать:

awk 'NF==5{printf "%.2e\t%.2e\t%.2e\t%.2e\t%.2e\n", $1, $2, $3, $4, $5; next}1' file 

Если число столбцов неизвестен использовать петлю:

awk '!/^step/{for(i=1;i<=NF;i++) printf "%.2e%s", $i,i==NF?"\n":"\t";next}1' file 
+1

Я не знаю априори, сколько столбцов есть. И может быть много больше 5, поэтому перечисление их один за другим не является вариантом. Можете ли вы улучшить это? – becko

+0

@becko: В этом случае вы можете использовать цикл (см. Редактирование). – user000001

+0

Цикл * очень * медленный, для больших файлов, которые я пытался. – becko