如何为 txt 文件中的每 2 行创建一个 csv 行
How to make a csv row for each 2 lines in a txt file
我有一个这样的文本文件:
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz
Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz
Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz
Tomato mottle virus
我需要得到这样的 csv
文件:
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
因为稍后我想像元组一样使用它来查找压缩文件,读取它并获得名称如下的最终文件:
Viruses/GCF_000837105.1/Tomato mottle virus.fna
我只需要学习如何做问题的第一部分。它可以通过:
- sed
- awk
- R
- Python
如有任何帮助,我们将不胜感激。这对我来说很难完成,因为原始文件名很乱。
我试过这个:
sed -z 's/\n/,/g;s/,$/\n/' multi_headers
然而它把逗号放在所有 \n
.
这个呢
with open('test.txt') as f:
data = f.read().split('\n')
new_data = []
for a in range(0,len(data),2):
new_data.append(data[a]+','+data[a+1]+'\n')
with open('result.txt','w') as f:
f.writelines(new_data)
或
with open('test.txt') as f_read, open('result.txt','w') as f_write:
data = f_read.read().split('\n')
new_data = []
for a in range(0,len(data),2):
new_data.append(data[a]+','+data[a+1]+'\n')
f_write.writelines(new_data)
使用sed
$ sed '/^Viruses/{N;s/\n\(.*\)/,/}' multi_headers
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
/^Viruses/
- 匹配以字符串 Viruses
开头的行
{N;
- Read/append下一行输入模式space.
s/\n\(.*\)/,/
- 从模式 space 中删除 \n 并将其替换为逗号 ,
Bash
你可以做一个paste
(感谢@glenn jackman 指出我之前无用的cat
)。
# or cat mytext.txt | paste -d "," - -
paste -d "," - - < mytext.txt
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
R
R函数也是paste
,加上sapply
:
mytext <- scan("mytext.txt", character(), sep = "\n")
sapply(seq(1, length(mytext), 2), function(x) paste(mytext[x], mytext[x + 1], sep = ","))
[1] "Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A"
[2] "Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA"
[3] "Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus"
在每个 Unix 机器上的任何 shell 中使用任何 awk,一次只在内存中存储 1 行,因此无论输入文件有多大,它都可以工作:
$ awk '{ORS=(NR%2 ? "," : RS)} 1' file
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
上面的少量代码发生了很多事情,所以这里有一个解释:
ORS
是内置变量,包含要在每个输出记录(本例中为 record = line)末尾打印的字符串,默认为换行符。
RS
是包含分隔每个输入记录的字符串(或正则表达式)的内置变量,默认为换行符。
NR
是包含当前 record/line 数字的内置变量,因此 NR%2
对于奇数记录为 1
,对于偶数记录为 0。
NR%2 ? "," : RS
是一个 ternary expression,对于奇数行,,
是 \n
(或者您将 RS
设置为的任何其他内容,例如 \r\n
) 对于偶数。
1
为真条件,导致执行打印当前记录的默认操作。
所以上面的脚本说“如果当前行号是奇数,则在末尾用 ,
打印它,否则在末尾用换行符打印它”,因此它用一个,
之间。
一个简单的writerows()
:
import csv
with open("text.txt", "r") as f:
with open("data.csv", "w", newline="") as w:
writer = csv.writer(w)
# May want to add headers
writer.writerow(["Heading1", "Heading2"])
x = f.readlines()
writer.writerows([x[i:i+2] for i in range(0, len(x), 2)])
产生:
Heading1,Heading2
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
另一种 R 方法,依赖向量回收。
t = readLines("txt.txt")
paste0(t[c(T, F)], ",", t[c(F, T)]) |> writeLines("txt.csv")
或最终文件名
t = readLines("R/txt.txt")
sub("(?<=\.\d).*", "", t, perl = T) |>
(\(.) paste0(.[c(T, F)], "/", .[c(F, T)], ".fna"))()
#> [1] "Viruses/GCF_000820355.1/Sclerophthora macrospora virus A.fna"
#> [2] "Viruses/GCF_000820495.2/Influenza B virus RNA.fna"
#> [3] "Viruses/GCF_000837105.1/Tomato mottle virus.fna"
简单python3
解决方案,令file.txt
内容为
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz
Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz
Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz
Tomato mottle virus
和script.py
with open("file.txt","r") as f:
for inx, line in enumerate(f):
print(line.rstrip(), end='\n' if inx%2 else ',')
然后
python script.py
输出
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
说明:我使用 .rstrip
丢弃尾随换行符,然后根据奇数行或偶数行分别应用 \n
或 ,
作为行尾。请注意,enumerate
默认从 0 开始,而不是 GNU AWK
从 1 开始。请注意,在文件句柄中使用 for ... 确实会阻止一次加载整个文件,因此该解决方案也可用于文件大于可用 RAM space.
这可能对你有用(GNU sed 和粘贴):
sed 'N;s/\n/,/' file
将下一行追加到当前行,然后用逗号替换换行符。
或:
paste -sd',\n' file
将文件粘贴为一个长字符串,用逗号替换每隔一个换行符。
要在混合中添加另一种解决方案,您还可以使用 xargs
并将输入行按 2 分组,然后在每个输出行中先将 space 替换为“,”。
xargs -n2 -d'\n' -a input.txt | sed 's/ /,/'
我有一个这样的文本文件:
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz
Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz
Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz
Tomato mottle virus
我需要得到这样的 csv
文件:
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
因为稍后我想像元组一样使用它来查找压缩文件,读取它并获得名称如下的最终文件:
Viruses/GCF_000837105.1/Tomato mottle virus.fna
我只需要学习如何做问题的第一部分。它可以通过:
- sed
- awk
- R
- Python
如有任何帮助,我们将不胜感激。这对我来说很难完成,因为原始文件名很乱。
我试过这个:
sed -z 's/\n/,/g;s/,$/\n/' multi_headers
然而它把逗号放在所有 \n
.
这个呢
with open('test.txt') as f:
data = f.read().split('\n')
new_data = []
for a in range(0,len(data),2):
new_data.append(data[a]+','+data[a+1]+'\n')
with open('result.txt','w') as f:
f.writelines(new_data)
或
with open('test.txt') as f_read, open('result.txt','w') as f_write:
data = f_read.read().split('\n')
new_data = []
for a in range(0,len(data),2):
new_data.append(data[a]+','+data[a+1]+'\n')
f_write.writelines(new_data)
使用sed
$ sed '/^Viruses/{N;s/\n\(.*\)/,/}' multi_headers
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
开头的行/^Viruses/
- 匹配以字符串Viruses
{N;
- Read/append下一行输入模式space.s/\n\(.*\)/,/
- 从模式 space 中删除 \n 并将其替换为逗号,
Bash
你可以做一个paste
(感谢@glenn jackman 指出我之前无用的cat
)。
# or cat mytext.txt | paste -d "," - -
paste -d "," - - < mytext.txt
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
R
R函数也是paste
,加上sapply
:
mytext <- scan("mytext.txt", character(), sep = "\n")
sapply(seq(1, length(mytext), 2), function(x) paste(mytext[x], mytext[x + 1], sep = ","))
[1] "Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A"
[2] "Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA"
[3] "Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus"
在每个 Unix 机器上的任何 shell 中使用任何 awk,一次只在内存中存储 1 行,因此无论输入文件有多大,它都可以工作:
$ awk '{ORS=(NR%2 ? "," : RS)} 1' file
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
上面的少量代码发生了很多事情,所以这里有一个解释:
ORS
是内置变量,包含要在每个输出记录(本例中为 record = line)末尾打印的字符串,默认为换行符。RS
是包含分隔每个输入记录的字符串(或正则表达式)的内置变量,默认为换行符。NR
是包含当前 record/line 数字的内置变量,因此NR%2
对于奇数记录为1
,对于偶数记录为 0。NR%2 ? "," : RS
是一个 ternary expression,对于奇数行,,
是\n
(或者您将RS
设置为的任何其他内容,例如\r\n
) 对于偶数。1
为真条件,导致执行打印当前记录的默认操作。
所以上面的脚本说“如果当前行号是奇数,则在末尾用 ,
打印它,否则在末尾用换行符打印它”,因此它用一个,
之间。
一个简单的writerows()
:
import csv
with open("text.txt", "r") as f:
with open("data.csv", "w", newline="") as w:
writer = csv.writer(w)
# May want to add headers
writer.writerow(["Heading1", "Heading2"])
x = f.readlines()
writer.writerows([x[i:i+2] for i in range(0, len(x), 2)])
产生:
Heading1,Heading2
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
另一种 R 方法,依赖向量回收。
t = readLines("txt.txt")
paste0(t[c(T, F)], ",", t[c(F, T)]) |> writeLines("txt.csv")
或最终文件名
t = readLines("R/txt.txt")
sub("(?<=\.\d).*", "", t, perl = T) |>
(\(.) paste0(.[c(T, F)], "/", .[c(F, T)], ".fna"))()
#> [1] "Viruses/GCF_000820355.1/Sclerophthora macrospora virus A.fna"
#> [2] "Viruses/GCF_000820495.2/Influenza B virus RNA.fna"
#> [3] "Viruses/GCF_000837105.1/Tomato mottle virus.fna"
简单python3
解决方案,令file.txt
内容为
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz
Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz
Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz
Tomato mottle virus
和script.py
with open("file.txt","r") as f:
for inx, line in enumerate(f):
print(line.rstrip(), end='\n' if inx%2 else ',')
然后
python script.py
输出
Viruses/GCF_000820355.1_ViralMultiSegProj14361_genomic.fna.gz,Sclerophthora macrospora virus A
Viruses/GCF_000820495.2_ViralMultiSegProj14656_genomic.fna.gz,Influenza B virus RNA
Viruses/GCF_000837105.1_ViralMultiSegProj14079_genomic.fna.gz,Tomato mottle virus
说明:我使用 .rstrip
丢弃尾随换行符,然后根据奇数行或偶数行分别应用 \n
或 ,
作为行尾。请注意,enumerate
默认从 0 开始,而不是 GNU AWK
从 1 开始。请注意,在文件句柄中使用 for ... 确实会阻止一次加载整个文件,因此该解决方案也可用于文件大于可用 RAM space.
这可能对你有用(GNU sed 和粘贴):
sed 'N;s/\n/,/' file
将下一行追加到当前行,然后用逗号替换换行符。
或:
paste -sd',\n' file
将文件粘贴为一个长字符串,用逗号替换每隔一个换行符。
要在混合中添加另一种解决方案,您还可以使用 xargs
并将输入行按 2 分组,然后在每个输出行中先将 space 替换为“,”。
xargs -n2 -d'\n' -a input.txt | sed 's/ /,/'