[英]Finding specific elements of a string read in from a .txt file in Java
我是Java的初學者,想知道如何從.txt文件中的DNA字符串中讀取特定元素。 例如,假設文本文件包含以下內容:
TAGAAAAGGGAAAGATAGT
我想知道如何最好地遍歷字符串並按順序查找特定的字符集。 一個示例是查找“ TAG”出現在讀入字符串中的次數。 這是我到目前為止的內容:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class DNA {
public static void main(String args[]) {
String fileName = args[0];
Scanner s = null;
try {
s = new Scanner(new File(fileName));
} catch (FileNotFoundException e) {
e.printStackTrace();
s.close();
}
String dna = "";
while(s.hasNext()) {
dna += s.next().trim();
}
s.close();
String subsequence = "TAG";
int count = 0;
for (int i = 0; i < dna.length(); i++){
if (dna.charAt(i) == subsequence.charAt(i)){
count = count + 1;
i++;
}
}
while (dna.charAt() == subsequence.charAt()){
count++;
}
System.out.println(subsequence + " appears " + count + " times");
}
}
雜亂無章,經過數小時的搜索,我試圖使用在其他示例中找到的邏輯。 請讓我知道我如何才能更有效率並使用更好的邏輯! 我喜歡學習這些東西,可以接受任何更正。
您可以使用子字符串來做到這一點。 由於TAG是3個字符,因此您可以在循環的每次迭代中從i-> i + 3中提取一個子字符串,然后與“ TAG”進行比較。
在AGAAAAGGGAAAGATAGT的示例中,循環將如下迭代:
“AGA” .equals( “TAG”)
“GAA” .equals( “TAG”)
“AAA” .equals( “TAG”)
“AAA” .equals( “TAG”)
“AAG” .equals( “TAG”)
“AGG” .equals( “TAG”)
“GGG” .equals( “TAG”)
等等
如果您不熟悉, 這里有關於子字符串的信息。 如果這不完全有意義,我可以嘗試解釋更多並提供偽代碼
在循環中,您要計算每個字符的出現次數,而不是子序列的出現次數。 您可以做的是比較子序列與:
Substring of dnb of length 3 characters starting from i
我說3個字符是因為您的子序列是"TAG"
。 您可以通過將子序列長度存儲在變量中來概括這一點。
您還需要檢查i + subsequence length
是否在字符串的范圍內。 否則,您將獲得IndexOutOfBoundsException
碼:
//current index i + sublen cannot exceed dna length
//portion of dna starting from i and going sublen characters has to equal subsequence
int countSubstring(String subsequence, String dna) {
int count = 0;
int sublen = subsequence.length(); // lenght of the subsequence
for (int i = 0; i < dna.length(); i++){
if ((i + sublen) < dna.length() &&
dna.substring(i, i + sublen).equals(subsequence)){
count = count + 1;
}
}
return count;
}
嘗試查看Rossetta代碼以獲取一些示例方法:
“刪除並計算差異”方法:
public int countSubstring(String subStr, String str){
return (str.length() - str.replace(subStr, "").length()) / subStr.length();
}
“分割並計數”方法:
public int countSubstring(String subStr, String str){
// the result of split() will contain one more element than the delimiter
// the "-1" second argument makes it not discard trailing empty strings
return str.split(Pattern.quote(subStr), -1).length - 1;
}
手動循環(類似於我在頂部顯示的代碼):
public int countSubstring(String subStr, String str){
int count = 0;
for (int loc = str.indexOf(subStr); loc != -1;
loc = str.indexOf(subStr, loc + subStr.length()))
count++;
return count;
}
對於特定程序,就從文件讀取而言,應將所有讀取操作放在try
塊中,然后在finally
塊中關閉資源。 如果您想了解更多關於Java I / O去這里並為finally
塊去這里 。 有很多方法可以從文件中讀取信息,我在這里向您展示了一種對代碼的更改最少的方法。
您可以將任何countSubstring
方法添加到您的代碼中,例如:
public static void main(String args[]) {
String fileName = args[0];
Scanner s = null;
String subsequence = "TAG";
String dna = "";
int count = 0;
try {
s = new Scanner(new File(fileName));
while(s.hasNext()) {
dna += s.next().trim();
}
count = countSubstring(subsequence, dna); // any of the above methods
System.out.println(subsequence + " appears " + count + " times");
} catch (FileNotFoundException e) {
e.printStackTrace();
// s.close(); Don't put s.close() here, use finally
} finally {
if(s != null) {
s.close();
}
}
}
然后,您有dna字符串和子序列字符串,
int count = (dna.length() - line.replace(subsequence, "").length())/subsequence.length();
要在不同的字符模式上搜索字符串,“ Pattern”和“ Matcher”類是一個很好的解決方案。
這是一些可以幫助您解決問題的代碼:
int count = 0;
String line = "T A G A A A A G G G A A A G A T A G T A G";
Pattern pattern = Pattern.compile("T A G");
Matcher matcher = pattern.matcher(line);
while (matcher.find())
count++;
System.out.println(count);
由Pattern.compile(String s)編譯的表達式稱為Regex。 在這種情況下,它只是在字符串中查找“ TAG”的出現。 使用while循環,您可以計算發生的次數。
如果您想做更復雜的事情,請查找有關正則表達式的更多信息。
讓我們嘗試一次計數多個密碼子,而不僅僅是計數TAG的實例。
public static final void main( String[] args )
{
String input = "TACACTAGATCGCACTGCTAGTATC";
if (args.length > 0) {
input = args[0].trim();
}
System.out.println(input);
HashMap<Character, Node> searchPatterns = createCodons();
findCounts(input, searchPatterns);
printCounts(searchPatterns);
}
該解決方案使用一棵樹來存儲我們感興趣的字符序列。 樹中從根到葉的每條路徑代表一個可能的序列。 我們將創建四棵樹; 以T,A,C和G開頭的密碼子。我們將這些樹存儲在HashMap中,以方便按其起始字符進行檢索。
/**
Create a set of sequences we are interesting in finding (subset of
possible codons). We could specify any pattern we want here.
*/
public static final HashMap<Character, Node> createCodons()
{
HashMap<Character, Node> codons = new HashMap<Character,Node>();
Node sequencesOfT = new Node('T'); // T
Node nodeA = sequencesOfT.addChild('A'); // /
nodeA.addChild('C'); // A
nodeA.addChild('G'); // / \
codons.put('T', sequencesOfT); // C G
Node sequencesOfA = new Node('A'); // A
Node nodeT = sequencesOfA.addChild('T'); // /
nodeT.addChild('C'); // T
nodeT.addChild('G');; // / \
codons.put('A', sequencesOfA); // C G
Node sequencesOfC = new Node('C'); // C
Node nodeG = sequencesOfC.addChild('G'); // /
nodeG.addChild('T'); // G
nodeG.addChild('A'); // / \
codons.put('C', sequencesOfC); // T A
Node sequencesOfG = new Node('G'); // G
Node nodeC = sequencesOfG.addChild('C'); // /
nodeC.addChild('T'); // C
nodeC.addChild('A'); // / \
codons.put('G', sequencesOfG); // T A
return codons;
}
這是我們的Node類的樣子。
public class Node
{
public char data; // the name of the node; A,C,G,T
public int count = 0; // we'll keep a count of occurrences here
public Node parent = null;
public List<Node> children;
public Node( char data )
{
this.data = data;
children = new ArrayList<Node>();
}
public Node addChild( char data )
{
Node node = new Node(data);
node.parent = this;
return (children.add(node) ? node : null);
}
public Node getChild( int index )
{
return children.get(index);
}
public int hasChild( char data )
{
int index = -1;
int numChildren = children.size();
for (int i=0; i<numChildren; i++)
{
Node child = children.get(i);
if (child.data == data)
{
index = i;
break;
}
}
return index;
}
}
為了計算出現次數,我們將迭代輸入的每個字符,並為每次迭代檢索我們感興趣的樹(A,G,C或T)。然后,我們嘗試沿着樹(從根到葉)走下)使用輸入的后續字符-當我們無法在節點的子代列表中找到輸入的下一個字符時,我們將停止遍歷。 在這一點上,我們增加該節點上的計數,以表明找到了一個在該節點結束的字符序列。
public static final void findCounts(String input, HashMap<Character,Node> sequences)
{
int n = input.length();
for (int i=0; i<n; i++)
{
char root = input.charAt(i);
Node sequence = sequences.get(root);
int j = -1;
int c = 1;
while (((i+c) < n) &&
((j = sequence.hasChild(input.charAt(i+c))) != -1))
{
sequence = sequence.getChild(j);
c++;
}
sequence.count++;
}
}
為了打印結果,我們將每棵樹從根到葉,在遇到它們時打印節點,並在到達葉子時打印計數。
public static final void printCounts( HashMap<Character,Node> sequences )
{
for (Node sequence : sequences.values())
{
printCounts(sequence, "");
}
}
public static final void printCounts( Node sequence, String output )
{
output = output + sequence.data;
if (sequence.children.isEmpty())
{
System.out.println(output + ": " + sequence.count);
return;
}
for (int i=0; i<sequence.children.size(); i++)
{
printCounts( sequence.children.get(i), output );
}
}
這是一些示例輸出:
TAGAAAAGGGAAAGATAGT
TAC: 0
TAG: 2
GCT: 0
GCA: 0
ATC: 0
ATG: 0
CGT: 0
CGA: 0
TAGCGTATC
TAC: 0
TAG: 1
GCT: 0
GCA: 0
ATC: 1
ATG: 0
CGT: 1
CGA: 0
從這里開始,我們可以輕松地擴展解決方案,以保留找到每個序列的位置的列表,或者記錄有關輸入的其他信息。 這種實現方式有些粗糙,但是希望它可以為您解決問題的其他方式提供一些見識。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.