查找从Java中的.txt文件读入的字符串的特定元素

时间:2014-09-13 18:42:23

标签: java string search

我是Java的初学者,我想知道如何从.txt文件中的一串DNA中读取特定元素。例如,假设文本文件包含以下内容:

G A A A G G G A A G A T A G T

我想知道如何最好地遍历字符串并按顺序查找特定的字符集。一个例子是找到多少次" 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");

}

}

它太乱了,我试图使用我在其他例子中经过多个小时的搜索后发现的逻辑。请让我知道如何更有效,并使用更好的逻辑!我喜欢学习这些东西,并愿意接受任何更正。

5 个答案:

答案 0 :(得分:0)

您可以使用子字符串来完成此操作。由于TAG是3个字符,您可以从i - &gt;中获取子字符串。 i + 3循环的每次迭代并与“TAG”进行比较。

在A G A A A A G G G A A A G A T A G T的例子中,循环将迭代如下:

“AGA” .equals( “TAG”)

“GAA” .equals( “TAG”)

“AAA” .equals( “TAG”)

“AAA” .equals( “TAG”)

“AAG” .equals( “TAG”)

“AGG” .equals( “TAG”)

“GGG” .equals( “TAG”)

等。

如果您不熟悉,子字符串上有信息here。如果这不完全有意义,我可以尝试解释更多并提供psuedocode

答案 1 :(得分:0)

在循环中,您计算​​每个字符的出现次数而不是子序列的出现次数。您可以做的是比较您的子序列与:

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 Code来寻找一些示例方法:

&#34;删除并计算差异&#34;方法:

public int countSubstring(String subStr, String str){
    return (str.length() - str.replace(subStr, "").length()) / subStr.length();
}

&#34>分裂和计数&#34;方法:

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的更多信息,请转到here,然后转到finally块,转到here。有很多方法可以从文件中读取信息,我只是向您展示了一个需要对代码进行最少更改的方法。

您可以在代码中添加任意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();
        }
    }
}

答案 2 :(得分:0)

你有dna String和subsequence String,然后

int count = (dna.length() - line.replace(subsequence, "").length())/subsequence.length();

答案 3 :(得分:0)

要在不同的字符模式上搜索字符串&#34; Pattern&#34;和#34;匹配&#34;课程是一个很好的解决方案。

以下是一些有助于解决问题的代码:

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。在这种情况下,它只是寻找&#34; T A G&#34;在字符串中。使用while循环可以计算出现的次数。

如果你想做更复杂的事情,请查看有关正则表达式的更多信息。

答案 4 :(得分:0)

不要只计算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)。然后我们尝试沿着树走下去(从root to leaf)使用输入的后续字符 - 当我们无法在节点的子节点列表中找到输入的下一个字符时,我们停止遍历。此时,我们在该节点上递增计数,以指示在该节点处找到的字符序列。

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

从这里我们可以轻松扩展解决方案,以保留每个序列的位置列表,或记录有关输入的其他信息。这种实现有点粗糙,但希望这可以为您解决问题的其他方式提供一些见解。

相关问题