[英]c++ appending text into a string until see a specific character
我有不止一個這樣的輸入文件:
>1aab_
GKGDPKKPRGKMSSYAFFVQTSREEHKKKHPDASVNFSEFSKKCSERWKT
MSAKEKGKFEDMAKADKARYEREMKTYIPPKGE
>1j46_A
MQDRVKRPMNAFIVWSRDQRRKMALENPRMRNSEISKQLGYQWKMLTEAE
KWPFFQEAQKLQAMHREKYPNYKYRPRRKAKMLPK
>1k99_A
MKKLKKHPDFPKKPLTPYFRFFMEKRAKYAKLHPEMSNLDLTKILSKKYK
ELPEKKKMKYIQDFQREKQEFERNLARFREDHPDLIQNAKK
>2lef_A
MHIKKPLNAFMLYMKEMRANVVAESTLKESAAINQILGRRWHALSREEQA
KYYELARKERQLHMQLYPGWSARDNYGKKKKRKREK
在這里,我必須做的:
vector <string> names;
vector <string> seqs;
names.resize(total); //"total" is already known.
seqs.resize(total);
counter=0;char input;
while ((input = myInput.get()) != EOF)
{
if(input=='>')
names[counter]= take all line (>1aab_, >1j46_A, so...)
else
untill the see next '>' append the character into sequence[counter]
counter++;
}
最后會是這樣:
names[0]=">1aab_"
sequence[0]="GKGDPKKPRGKMSSYAFFVQTSREEHKKKHPDASVNFSEFSKKCSERWKTMSAKEKGKFEDMAKADKARYEREMKTYIPPKGE"
等等..
我想了2個小時,我想不通。 任何人都可以幫忙嗎? 提前致謝。
有幾種方法可以解決它; 我將提供一些示例,但我不會測試/編譯此代碼,因此可能存在小錯誤 - 邏輯是重要的一點。
由於您的偽代碼似乎正在逐個字符地處理輸入,因此我將其視為一項要求。
您似乎正在考慮的方式基本上是通過一對循環來實現的——一個用於讀取名稱,另一個用於讀取序列——它們包含在外部循環中,以便處理所有記錄。
這將類似於以下內容:
// first character in file should be a '>', indicating the start
// of a record.
input = myInput.get();
if (input != '>')
{
std::cerr << "Malformed input file!" << std::endl;
return /*...*/;
}
do
{
// record name continues up until the newline
while ((input = myInput.get()) != EOF)
{
if (input == '\n' || input == '\r')
break;
names[counter].push_back(input);
}
// read sequence until we hit a '>' or EOF
while ((input = myInput.get()) != EOF)
{
if (input == '>')
{
// advance to next record number
counter++;
break;
}
sequence[counter].push_back(input);
}
} while (input != EOF && counter < total);
您還會注意到我將初始 '>' 的檢查移到循環之前,這只是作為攝取(和丟棄)字符的一種方式,以及對輸入的基本完整性檢查。 這是因為我們真的使用這個字符來標記序列的結束(而不是“記錄的開始”)——當我們進入循環時,我們假設我們已經在讀取記錄名稱。
另一種方法是使用狀態機。 本質上,這利用額外的變量來跟蹤解析器所處的狀態。
對於這種特殊情況,您只有兩種狀態:您正在讀取記錄名稱或序列。 所以,我們可以只使用一個布爾值來跟蹤我們所處的狀態。
有了狀態變量,我們就可以根據我們所處的狀態決定如何處理我們剛剛讀取的字符。 在最簡單的層面上,如果我們處於“讀取記錄名稱”狀態,我們將字符添加到names
變量中,否則我們將其添加到sequence
變量中。
// state flag to indicate if we're currently reading a name line,
// i.e. a line starting with ">"
// This should be set true by the first record we encounter, so
// we'll set it false (to indicate we're reading a sequence) in
// order to allow us to detect bad input files.
bool reading_name = false;
// indicate we're on the first record, so we can avoid incrementing
// the record counter
bool first_record = true;
// process input character-by-character until end of file
while ((input = myInput.get()) != EOF)
{
// check for start of new record
if (input == '>')
{
// for robustness, verify we're not already reading a name,
// as this probably indicates invalid input
if (reading_name)
{
std::cerr << "Input is malformed?!" << endl;
break;
}
// switch to reading name state
reading_name = true;
// advance to next record, but only if it isn't the first record
if (first_record)
{
// disable the first_record flag, and explicitly set the
// record counter to 0.
first_record = false;
counter = 0;
}
else if (++counter >= total)
{
std::cerr << "Error: too many records!" << std::endl;
break;
}
}
// first character in file should start a new record
else if (first_record)
{
std::cerr << "Missing record start character at beginning of input!" << std::endl;
break;
}
// make sure we are processing a valid record number
else if (counter >= total)
{
std::cerr << "Invalid record number!" << std::endl;
break;
}
// continue reading the name
else if (reading_name)
{
// check if we've reached the end of the line; you
// may also want/need to check for \r if your input
// files may have Windows-style line endings
if (input == '\n')
{
// switch to reading sequence state
reading_name = false;
}
else
{
// add character to current name
names[counter].push_back(input);
}
}
// continue reading the sequence
else
{
// you might need to handle line ending characters here,
// maybe just skipping them?
// add character to current sequence
sequence[counter].push_back(input);
}
}
這增加了相當多的復雜性,這對於此特定練習的價值值得懷疑,但確實使將來添加其他狀態更容易。 它還具有代碼中只有一個地方完成 I/O 的好處,這減少了出錯的機會(不檢查 EOF、溢出數組邊界等)。
在這種情況下,我們實際上使用 '>' 字符作為新記錄開始的指示符,因此我們添加了一些額外的邏輯以確保所有記錄計數器都能正常工作。 您也可以只為counter
變量使用有符號整數並從-1
開始,因此它將在第一條記錄的開頭增加到 0,但使用有符號變量來索引數組並不是一個好主意。
有更多方法可以解決這個問題,但希望這可以為您提供開始自己解決方案的地方。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.