以特定方式格式化文本文件
Format text file in particular way
我有一个巨大的文本文件,内容如下:
1|ROW1|IDA|IDB|Z|OP
2|ROW2|IDA|IDC|IDF|IDG|Z|OP
3|ROW3|IDA|IDC|IDF|Z|OP
我想通过像这样展平 ID
列来格式化它:
1|ROW1|IDA|Z|OP
1|ROW1|IDB|Z|OP
2|ROW2|IDA|Z|OP
2|ROW2|IDC|Z|OP
2|ROW2|IDF|Z|OP
2|ROW2|IDG|Z|OP
3|ROW3|IDA|Z|OP
3|ROW3|IDC|Z|OP
3|ROW3|IDF|Z|OP
在脚本中有没有简单的方法可以做到这一点?或者我是否需要编写一个小程序来读取每一行并通过正则表达式匹配一行的每一列?
感谢您的提示
我会在这里使用 Python 脚本和 csv
模块:
with open('input.txt') as fdin, open('output.txt', 'w', newline='') as fdout:
rd = csv.reader(fdin, delimiter='|')
wr = csv.writer(fdout, delimiter='|')
for row in rd:
for item in row[2:-2]:
_ = wr.writerow(row[:2] + [item] + row[-2:])
如果你愿意考虑awk,你可以这样做:
awk -F'|' '{
last = 2
for(i = 3; i <= NF; ++i) {
if($i~/^ID/) last = i;
else break;
}
for(i = 3; i <= last; ++i) {
printf("%s|%s|%s", , , $i);
for(j = last + 1; j <= NF; ++j) {
printf("|%s", $j);
}
printf("\n");
}
}'
对于字段由 |
分隔的每一行(-F'|'
参数),这是完成的:
- 第一个循环查找以
ID
开头的最后一个字段(/^ID/
部分)。
- 下一个循环遍历
ID
字段并打印字段 1 和 2,然后是当前 ID
字段。
- 内部循环打印
ID
字段之后的所有字段。
可能更易于阅读和维护的版本:
awk -F'|' '{
last = 2;
for(i = 3; i <= NF; ++i) {
if($i~/^ID/) last = i;
else break;
}
last_fields = ""
for(i = last + 1; i <= NF; ++i) {
last_fields = last_fields "|" $i;
}
for(i = 3; i <= last; ++i) {
printf("%s|%s|%s%s\n", , , $i, last_fields);
}
}'
- 第一个循环查找以
ID
. 开头的最后一个字段
- 第二个循环在最后一个
ID
字段 之后的字段中构建一个变量 (last_fields
)
- 第三个循环打印字段 1、2,当前
ID
字段然后是 last_fields
.
这是一个使用正则表达式的 Notepad++ 解决方案。在 Notepad++ 7.9.1 上测试。
查找:^(.*?\|)(ID\w\|)((?:ID\w\|)+)(.*)$
。
替换为:\r\n
。
Select 正则表达式和环绕,不要 select 点匹配换行符。
重复执行全部替换,直到不再进行替换。所需的全部替换命令的数量将比行中 IDx 字符串的最大数量少一个。
查找字符串的解释:
^(.*?\|) Group 1: Matches leading characters on the line
(ID\w\|) Group 2: Matches the first IDx and its following |
( Group 3 starts
(?:ID\w\|)+ Matches all remaining IDx's and their following |, this is a non-capturing group
) Group 3 ends
(.*)$ Group 4: Everything on line after the last IDx and |
替换字符串输出两行。第一个具有包含第一个 IDx(第 2 组)的开始(第 1 组)和结束(第 4 组)文本。第二行包含围绕其他 IDx 字符串(第 3 组)的开始和结束文本。
我有一个巨大的文本文件,内容如下:
1|ROW1|IDA|IDB|Z|OP
2|ROW2|IDA|IDC|IDF|IDG|Z|OP
3|ROW3|IDA|IDC|IDF|Z|OP
我想通过像这样展平 ID
列来格式化它:
1|ROW1|IDA|Z|OP
1|ROW1|IDB|Z|OP
2|ROW2|IDA|Z|OP
2|ROW2|IDC|Z|OP
2|ROW2|IDF|Z|OP
2|ROW2|IDG|Z|OP
3|ROW3|IDA|Z|OP
3|ROW3|IDC|Z|OP
3|ROW3|IDF|Z|OP
在脚本中有没有简单的方法可以做到这一点?或者我是否需要编写一个小程序来读取每一行并通过正则表达式匹配一行的每一列?
感谢您的提示
我会在这里使用 Python 脚本和 csv
模块:
with open('input.txt') as fdin, open('output.txt', 'w', newline='') as fdout:
rd = csv.reader(fdin, delimiter='|')
wr = csv.writer(fdout, delimiter='|')
for row in rd:
for item in row[2:-2]:
_ = wr.writerow(row[:2] + [item] + row[-2:])
如果你愿意考虑awk,你可以这样做:
awk -F'|' '{
last = 2
for(i = 3; i <= NF; ++i) {
if($i~/^ID/) last = i;
else break;
}
for(i = 3; i <= last; ++i) {
printf("%s|%s|%s", , , $i);
for(j = last + 1; j <= NF; ++j) {
printf("|%s", $j);
}
printf("\n");
}
}'
对于字段由 |
分隔的每一行(-F'|'
参数),这是完成的:
- 第一个循环查找以
ID
开头的最后一个字段(/^ID/
部分)。 - 下一个循环遍历
ID
字段并打印字段 1 和 2,然后是当前ID
字段。 - 内部循环打印
ID
字段之后的所有字段。
可能更易于阅读和维护的版本:
awk -F'|' '{
last = 2;
for(i = 3; i <= NF; ++i) {
if($i~/^ID/) last = i;
else break;
}
last_fields = ""
for(i = last + 1; i <= NF; ++i) {
last_fields = last_fields "|" $i;
}
for(i = 3; i <= last; ++i) {
printf("%s|%s|%s%s\n", , , $i, last_fields);
}
}'
- 第一个循环查找以
ID
. 开头的最后一个字段
- 第二个循环在最后一个
ID
字段 之后的字段中构建一个变量 ( - 第三个循环打印字段 1、2,当前
ID
字段然后是last_fields
.
last_fields
)
这是一个使用正则表达式的 Notepad++ 解决方案。在 Notepad++ 7.9.1 上测试。
查找:^(.*?\|)(ID\w\|)((?:ID\w\|)+)(.*)$
。
替换为:\r\n
。
Select 正则表达式和环绕,不要 select 点匹配换行符。
重复执行全部替换,直到不再进行替换。所需的全部替换命令的数量将比行中 IDx 字符串的最大数量少一个。
查找字符串的解释:
^(.*?\|) Group 1: Matches leading characters on the line
(ID\w\|) Group 2: Matches the first IDx and its following |
( Group 3 starts
(?:ID\w\|)+ Matches all remaining IDx's and their following |, this is a non-capturing group
) Group 3 ends
(.*)$ Group 4: Everything on line after the last IDx and |
替换字符串输出两行。第一个具有包含第一个 IDx(第 2 组)的开始(第 1 组)和结束(第 4 组)文本。第二行包含围绕其他 IDx 字符串(第 3 组)的开始和结束文本。