我正在研究FASTA文件。 FASTA文件在生物学中用于存储序列。
> sequence1标识符(字符串)
一条或多条线上的序列(一个字符串)
...
>最后一个序列标识符(一个字符串)
一条或多条线上的序列(一个字符串)
我想创建一个在读取文件时返回结构的迭代器:
struct fasta_seq {
identifier: String,
sequence: String,
}
在Python中,它很容易。这段代码返回一个元组,但想法是相同的
def get_seq_one_by_one(file_):
"""Generator return prompt sequence for each sequence"""
sequence = ''
prompt = ''
for line in file_:
if line.startswith('>'):
if sequence:
yield (prompt, sequence)
sequence = ''
prompt = line.strip()[1:]
else:
sequence += line.strip()
yield (prompt, sequence)
这很方便,并且允许我制作更清晰的代码,因为我可以使用简单的for循环遍历文件。
for identifier, sequence in get_seq_one_by_one(open_file):
do
我发现了类似的主题:
如果我理解正确,他们知道要读取的缓冲区的大小。 在我的情况下,我不知道它,因为标识符和/或序列长度可能会改变。
我已经检查并使用Rust的yield
似乎不是一个好主意,因为它被描述为不稳定。
我不希望你在我的位置编写代码,我试图通过重写我在Rust中用Python完成的脚本来学习。我不知道在这里用什么来回答我的问题。
如果你能指出如何实现这一目标的总体思路,那将是非常好的。如果不需要不安全的代码,它会更好。
答案 0 :(得分:0)
正如评论中所说,更好的是使用an existing crate。如果您希望绝对编写自己的代码,则必须尝试以下内容:
use std::io::Read;
use std::fs::File;
struct FastaSeq {
identifier: String,
sequence: String,
}
fn main() {
fn process_file(file_name: &str) -> Result<Vec<FastaSeq>, std::io::Error> {
let mut lines = String::new();
File::open(file_name)?.read_to_string(&mut lines)?;
let mut ret = Vec::new();
let mut lines = lines.split('\n');
// I assume that the first line begin with '>'
while let Some(line) = lines.by_ref().next() {
ret.push(FastaSeq {
identifier: line.into(),
sequence: lines
.by_ref()
.take_while(|s| s.chars().next().map(|c| c != '>').unwrap_or(false))
.collect(),
});
}
Ok(ret)
}
if let Err(e) = process_file("your file") {
println!("An error occured: {}", e);
std::process::exit(1);
}
}
答案 1 :(得分:0)
我设法得到了一些工作。它显然是一个初学者级别的实现,但它的工作原理。
struct FastaSeq {
identifier: String,
sequence: String,
}
// come from: https://docs.rs/bio/0.17.0/src/bio/io/fasta.rs.html#7-1013
struct FastaReader<R: io::Read> {
reader: io::BufReader<R>,
}
// come from: https://docs.rs/bio/0.17.0/src/bio/io/fasta.rs.html#7-1013
impl<R: io::Read> FastaReader<R> {
/// Create a new Fasta reader given an instance of `io::Read`.
pub fn new(reader: R) -> Self {
FastaReader {
reader: io::BufReader::new(reader),
}
}
}
impl<B: BufRead> Iterator for FastaReader<B> {
type Item = Result<FastaSeq, io::Error>;
fn next(&mut self) -> Option<Result<FastaSeq, io::Error>> {
let mut this_string = String::new();
let mut buf = vec![];
match self.reader.read_until(b'>', &mut buf) {
Ok(0) => None,
Ok(my_buf) => {
this_string = from_utf8(&buf).unwrap().to_string();
if this_string == ">" {
self.reader.read_until(b'>', &mut buf);
this_string = from_utf8(&buf).unwrap().to_string();
}
this_string = this_string.trim_matches('>').to_string();
let split_str = this_string.split("\n");
let split_vec = split_str.collect::<Vec<&str>>();
let identifier = split_vec[0];
let sequence = split_vec[1..].join("");
return Some(Ok(FastaSeq {
identifier: identifier.to_string(),
sequence: sequence.to_string(),
}));
}
Err(e) => Some(Err(e)),
}
}
}