我正在处理以下数据以获得第一列和第五列,将格式转换D
为E
格式并删除包含乱码的行,例如9.410-316
.
DEG = 1.500
2.600D+01 0.000D+00 0.000D+00 0.000D+00 0.000D+00
2.700D+01 8.720-304 2.369-316 7.556-316 9.410-316
4.300D+01 1.208D-83 4.156D-96 7.360D-96 6.984D-96
1.590D+02 8.002D-07 6.555D-19 7.748D-19 7.376D-19
1.600D+02 1.173D-06 9.669D-19 1.143D-18 1.089D-18
1.610D+02 1.709D-06 1.417D-18 1.676D-18 1.596D+01
1.620D+02 2.468D-06 2.058D-18 2.436D-18 2.320D-10
DEG = 18.500
2.700D+01 2.794-314 0.000D+00 0.000D+00 0.000D+00
2.800D+01 4.352-285 1.224-297 3.685-297 4.412-297
8.800D+01 1.371D-02 6.564D-15 7.852D-15 7.275D-15
我的问题是确定要删除的数字格式。到目前为止,我已经尝试过
maxa=18.5
maxangle=$(printf "%.3f" $maxa)
if (( $(echo "$maxa < 10" | bc -l) )); then
txt2search="DEG = $maxangle"
# 6 spaces between = and value if deg=>10, else only 5)
else
txt2search="DEG = $maxangle"
fi
line=$(grep -n "$txt2search" file | cut -d : -f 1)
# Once the line number is read for the string, skip a few lines (4) and read next several lines(1000)
beginline=$((line + 4))
endline=$((line + 1002))
awk -v a="$beginline" -v b="$endline" 'NR==a, NR==b {print $1, $5}' fileinput > fileoutput
sed -i 's/D/E/g' fileoutput
然后,为了丢弃带有无意义数字的行,我尝试(一次一个)并使用以下命令失败了。
sed -ni '/E/p' fileoutput
sed -E '/(E)/!d' fileoutput > spec2.tempdata
sed '/E/!d' fileoutput > spec2.tempdata
awk '!/E/' fileoutput > spec2.tempdata
如何识别并删除带有此类无意义数字的行?版本是
- sed(GNU sed)4.7
- grep (GNU grep) 3.4
- GNU Awk 5.0.1,API:2.0(GNU MPFR 4.0.2,GNU MP 6.2.0)
输出将是
2.600D+01 0.000D+00 0.000D+00 0.000D+00 0.000D+00
4.300D+01 1.208D-83 4.156D-96 7.360D-96 6.984D-96
1.590D+02 8.002D-07 6.555D-19 7.748D-19 7.376D-19
1.600D+02 1.173D-06 9.669D-19 1.143D-18 1.089D-18
1.610D+02 1.709D-06 1.417D-18 1.676D-18 1.596D+01
1.620D+02 2.468D-06 2.058D-18 2.436D-18 2.320D-10
编辑:我正在寻找的解决方案是(参见第一条评论)
grep -v '[0-9]-'
答案1
使用乐(以前称为 Perl_6)
~$ raku -e 'my @a; for lines.join("\n").split(/ \n <?before DEG> /) { @a.push: %(.split("\n").[0].words.[2] => \
.split("\n")[1..*].map(*.words[0,4])>>.map(*.subst( / (\d+) (<[+-]>) /, {$0 ~ "e" ~ $1} ).subst(/D/, "e") )>>.Num) }; \
.raku.put for @a;' file
用于可视化目的的示例输出:
${"1.500" => $($(26e0, 0e0), $(27e0, 9.41e-316), $(43e0, 6.984e-96), $(159e0, 7.376e-19), $(160e0, 1.089e-18), $(161e0, 15.96e0), $(162e0, 2.32e-10))}
${"18.500" => $($(27e0, 0e0), $(28e0, 4.412e-297), $(88e0, 7.275e-15))}
Raku 是 Perl 家族中的一种编程语言,具有有理数和内置 Unicode 支持。上面,一般策略是创建一个哈希数组,第 1 列和第 5 列(索引)中的DEG
值为和测量值。key
[0,4]
value
@
声明了 -sigiled 数组 ( ) @a
。 Raku 代码会自动读取lines
,join
并在换行符上将它们重新组合在一起\n
。从这里开始,我们通过split
查找\n
之前出现的换行符来打破记录DEG
。进入该{ … }
块,每个记录再次split
换\n
行,.[0].words.[2]
第一个元素的第三个单词变成key
.粗=>
箭头表示“对”结构,成为value
.请注意这两个.subst
调用:第一个调用在数字和由加号或减号\d
组成的定制字符类之间插入“e”,第二个调用将“D”更改为“e”。<[+-]>
值被转换为.Num
,并将%( … )
哈希值推送到@a
数组中。该.raku
方法被添加到输出行,以实现 Raku 数据内部表示的可视化(note.perl
也可用作同义词)。
绘图的实际输出:
更改最后一行.raku.put for @a
以获得所需的绘图输出。下面是一些示例(如果需要,您也可以使用 Rakuprintf
或sprintf
):
1.替换put
上面的 out 行以返回第一个DEG
:
for @a[0].kv -> $k,$v {put ([Z] $k xx $v.elems, $v).join: "\n"}
#Returns 3-columns:
1.500 26 0
1.500 27 9.41e-316
1.500 43 6.984e-96
1.500 159 7.376e-19
1.500 160 1.089e-18
1.500 161 15.96
1.500 162 2.32e-10
2.或者使用以下行立即返回整个 3 列表put
:
for @a { for ($_.kv) -> $k,$v {put ([Z] $k xx $v.elems, $v).join: "\n"}};
#Returns:
1.500 26 0
1.500 27 9.41e-316
1.500 43 6.984e-96
1.500 159 7.376e-19
1.500 160 1.089e-18
1.500 161 15.96
1.500 162 2.32e-10
18.500 27 0
18.500 28 4.412e-297
18.500 88 7.275e-15
3. 最后: Raku 有一个=~=
“公差”运算符,可用于确定值是否约为。等于 0(默认为 1e-15,请参阅下面的链接)。把它们放在一起:
~$ raku -e 'my @a; for lines.join("\n").split(/ \n <?before DEG> /) { @a.push: %(.split("\n").[0].words.[2] => \
.split("\n")[1..*].map(*.words[0,4])>>.map(*.subst( / (\d+) (<[+-]>) /, {$0 ~ "e" ~ $1} ).subst(/D/, "e") )>>.Num) }; \
for @a { for ($_.kv) -> $k,$v {put ([Z] $k xx $v.elems, $v>>.map( -> $i { ($i =~= 0) ?? 0 !! $i } )).join: "\n"}};' file
1.500 26 0
1.500 27 0
1.500 43 0
1.500 159 0
1.500 160 0
1.500 161 15.96
1.500 162 2.32e-10
18.500 27 0
18.500 28 0
18.500 88 7.275e-15
https://docs.raku.org/language/hashmap.html
https://docs.raku.org/language/5to6-nutshell.html#=%3E_Fat_comma
https://docs.raku.org/routine/=~=.html
https://raku.org
答案2
FWIW 以下是如何将输入中的 D 更改为 E,然后通过比较添加之前和之后的值来判断字段是否为数字0
(数字将保留其值,非数字则不会)
$ awk 'NF>3{gsub(/D/,"E"); for (i=1; i<=NF; i++) if ($i != $i+0) print "not a number:", $i}' file
not a number: 8.720-304
not a number: 2.369-316
not a number: 7.556-316
not a number: 9.410-316
not a number: 2.794-314
not a number: 4.352-285
not a number: 1.224-297
not a number: 3.685-297
not a number: 4.412-297
因此打印仅包含数字的行将是:
$ awk 'NF>3{gsub(/D/,"E"); for (i=1; i<=NF; i++) if ($i != $i+0) next; print}' file
2.600E+01 0.000E+00 0.000E+00 0.000E+00 0.000E+00
4.300E+01 1.208E-83 4.156E-96 7.360E-96 6.984E-96
1.590E+02 8.002E-07 6.555E-19 7.748E-19 7.376E-19
1.600E+02 1.173E-06 9.669E-19 1.143E-18 1.089E-18
1.610E+02 1.709E-06 1.417E-18 1.676E-18 1.596E+01
1.620E+02 2.468E-06 2.058E-18 2.436E-18 2.320E-10
8.800E+01 1.371E-02 6.564E-15 7.852E-15 7.275E-15
或者:
$ awk 'NF>3{gsub(/D/,"E"); for (i=1; i<=NF; i++) if ($i != $i+0) next} 1' file
DEG = 1.500
2.600E+01 0.000E+00 0.000E+00 0.000E+00 0.000E+00
4.300E+01 1.208E-83 4.156E-96 7.360E-96 6.984E-96
1.590E+02 8.002E-07 6.555E-19 7.748E-19 7.376E-19
1.600E+02 1.173E-06 9.669E-19 1.143E-18 1.089E-18
1.610E+02 1.709E-06 1.417E-18 1.676E-18 1.596E+01
1.620E+02 2.468E-06 2.058E-18 2.436E-18 2.320E-10
DEG = 18.500
8.800E+01 1.371E-02 6.564E-15 7.852E-15 7.275E-15
取决于您是否想要DEG
输出这些行。