我有一个 .data,我需要重新组织它,以便将 3 个连续的行合并为一行。为了清楚起见,我有以下内容...
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,
C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,
A = 0.007425, ALP = 1.000000, EPS = 1.000000,
FX = -0.355305, FY = 0.857782, FZ = 0.282590;
...等等
我需要将所有内容放在一行中:
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,C = 3.341441E-006 * Cp_SVM_PRS_Pi001 ...
我需要它来查看整个文档。有没有快速的方法?
另一个困难是,所有要合并的信息有时在 3 行,有时在 2 行或 4 行。我唯一能想到的是每行都用 D 来标识……可以做到吗?怎么做?
基本上,每行新行都应以节点号 D611102 开头。我需要一行大行,其中 T = ...、C = ...,直到 FZ = .... 等。每行都必须包含直到 ; 的所有数据
为了更清楚,我有以下内容:......
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,
C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,
A = 0.007425, ALP = 1.000000, EPS = 1.000000,
FX = -0.355305, FY = 0.857782, FZ = 0.282590;
D611103 = 'SVM_PRS_Hydr_L01', T = 0.0,
C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,
A = 0.007425, ALP = 1.000000, EPS = 1.000000,
FX = -0.656518, FY = 0.656518, FZ = 0.282590;
...等等...我需要这个:
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,A = 0.007425, ALP = 1.000000, EPS = 1.000000,FX = -0.355305, FY = 0.857782, FZ = 0.282590; (all in a single line)
D611103 = 'SVM_PRS_Hydr_L01', T = 0.0,C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,A = 0.007425, ALP = 1.000000, EPS = 1.000000,FX = -0.656518, FY = 0.656518, FZ = 0.282590;
(所有内容都在一行中),整个文档也是如此。
答案1
如果我理解正确的话,你基本上想要删除所有不直接出现在 之后的换行符;
。如果是这样,你可以这样做:
perl -pe 's/(?<!;)\s*\n/ /' file > newfile
或者,要就地编辑文件,请使用-i
:
perl -i.bak -pe 's/(?<!;)\s*\n/ /' file
上述操作将对 进行更改file
并创建原始的备份,名为file.bak
。若要跳过创建备份,只需-i
单独使用,无需扩展名。
解释
的意思-p
是“应用 给出的脚本后打印每一行输入-e
。s///
是替换运算符。它的一般格式是s/pattern/replacement/
并将 替换pattern
为replacement
。
在这种情况下,pattern
是 0 个或更多空格字符 ( \s*
),后跟换行符 ( \n
),且前面没有;
。该(?<!foo)bar
构造是负面后视bar
,如果前面的字符不是 ,它将匹配foo
。因此,上面的脚本将删除所有不在 之后的换行符;
。
答案2
下面的脚本应该可以完成这项工作。由于它是按行读取的,因此在处理较大的文件时应该相对较快,但我没有在大型文件上进行测试。
#!/usr/bin/env python3
import sys
f = sys.argv[1]
s = ""
with open(f) as lines:
for l in lines:
if l.startswith("D"):
print(s+l.strip(), end = "")
s = "\n"
else:
print(l.strip(), end = "")
用它
- 将其复制到空文件中,另存为
combine_lines.py
通过命令运行:
python3 /path/to/combine_lines.py <.data_file>
解释
脚本逐行读取行。如果行以 开头D
,则该行将打印在现有行之后,除了第一行。
测试:
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,
A = 0.007425, ALP = 1.000000, EPS = 1.000000,
FX = -0.355305, FY = 0.857782, FZ = 0.282590;
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,
A = 0.007425, ALP = 1.000000, EPS = 1.000000,
FX = -0.355305, FY = 0.857782, FZ = 0.282590;
变成:
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,A = 0.007425, ALP = 1.000000, EPS = 1.000000,FX = -0.355305, FY = 0.857782, FZ = 0.282590;
D611102 = 'SVM_PRS_Hydr_L01', T = 0.0,C = 3.341441E-006 * Cp_SVM_PRS_Pi001 * Dens_SVM_PRS_Pi001,A = 0.007425, ALP = 1.000000, EPS = 1.000000,FX = -0.355305, FY = 0.857782, FZ = 0.282590;
编辑
或者,
按照@terdon的建议,使用结尾的“;”作为触发器,这使我们有机会跳过这个s =
技巧:
#!/usr/bin/env python3
import sys
f = sys.argv[1]
with open(f) as lines:
for l in lines:
l = l if l.endswith(";\n") else l.strip(); print(l, end = "")
Perl 与 Python 的比较
在一个相对较大的文件上,550MB,9006121 行:
Perl:
$ time perl -pe 's/(?<!;)\s*\n/ /' '/home/jacob/Bureaublad/data_large' > '/home/jacob/Bureaublad/data_large2'
real 0m27.171s
user 0m25.536s
sys 0m1.054s
Python:
time '/home/jacob/Bureaublad/pscript_9.py' '/home/jacob/Bureaublad/data_large' > '/home/jacob/Bureaublad/data_large2'
real 0m15.235s
user 0m13.806s
sys 0m1.279s
在较小的文件(51KB,838 行)上:
$ time perl -pe 's/(?<!;)\s*\n/ /' '/home/jacob/Bureaublad/data_small' > '/home/jacob/Bureaublad/data_small2'
real 0m0.008s
user 0m0.007s
sys 0m0.000s
Python:
$ time '/home/jacob/Bureaublad/pscript_9.py' '/home/jacob/Bureaublad/data_small' > '/home/jacob/Bureaublad/data_small2'
real 0m0.033s
user 0m0.019s
sys 0m0.011s
底线是,如果您有更大的文件,python
可能这就是您想要使用的,如果您有许多较小的文件,Perl
则是更好的选择。