[英]finding, and then efficiently replacing with the reverse in java
我正在使用Java處理具有很大的蛋白質.txt文件數據庫。 這些蛋白質具有一般的結構,但沒有一個足夠統一的結構來硬編碼“將其從startIndex轉移到endIndex,反向並替換”。 唯一真正的統一性是它們之間用>
分隔,例如:
...WERINWETI>gi|230498 [Bovine Albumin]ADFIJWOENAONFOAIDNFKLSADNFATHISDATFDAIFJ>sp|234235 (human) AGP1 QWIQWONOQWNROIWQRNOQWIRNSWELLE>gi|...
等。
如您所見,盡管實際蛋白質序列(所有大寫字母的長鏈)是統一的,因為它們是大寫字母的鏈,但是除此之外,前面的描述幾乎可以是任何東西(很多時候沒有空格)在說明和順序之間)。 我的程序需要做的是將原始文本復制到一個新文件中,然后遍歷,在每個>
之后添加一個r-
(例如...EERFDS>r-gi|23423...
),然后僅反向資本鏈。 該過程完成后,我需要將其附加到原始文本的末尾。
我已經完成了r-
函數,實際上我也已經完成了逆轉和追加操作,但是效率不夠。 正在接受這種處理的數據庫是MASSIVE,我的程序花了太長時間。 實際上,我不知道要花多長時間,因為我從未讓它完成。 我等了1個小時就結束了。 這是我使用正則表達式(內置Pattern類)(計算密集型部分)進行逆運算的算法:
Pattern regexSplit = Pattern.compile(">");
String[] splits = regexSplit.split(rDash.toString());
StringBuilder rDashEdited = new StringBuilder();
Pattern regexProtein = Pattern.compile("[A-Z]{5,}");
for (int splitIndex = 1; splitIndex < splits.length; splitIndex++) {
Matcher rDashMatcher = regexProtein.matcher(splits[splitIndex]);
rDashMatcher.find();
StringBuffer reverser = new StringBuffer(rDashMatcher.group());
rDashEdited.append(rDashMatcher.replaceAll(reverser.reverse().toString()) + ">");
}
System.out.println(">" + rDashEdited);
因此,基本上,我將rDash
(這是一個StringBuilder,其中包含所有已插入>r-
所有原始蛋白質,但尚未經過逆轉)分解為每個蛋白質,並將它們添加到String數組中。 然后,我遍歷數組中的每個字符串,尋找長度超過5個字母的大寫字母鏈,將匹配項添加到StringBuffer中,將其反轉,然后將反向版本替換為反向。 請注意,此算法按預期適用於較小的文本文件。
是否有更強大的正則表達式消除了拆分/遍歷數組的需要? 當我嘗試時, replaceAll()
調用將所有下游蛋白質替換為集合中FIRST蛋白質的逆序。 我用System.out.println(rDashMatcher.groupCount())
進行了有趣的檢查,並為集合中的每種蛋白質打印了0
。 誰能幫助我使用更高效/更強大的正則表達式? 對我來說,這是一個相當新的概念,但它使我想起了在MATLAB中進行矢量化的過程(僅使用字母)。
我為此扔了10,000,000條記錄(大約379MB文本文件),並花了1:06分鍾。(4core athlon,幾年前)
大的if樹處理只得到一半的末端,因為定界符位於元素的中間。
public void readProteins(BufferedReader br, BufferedWriter bw) throws IOException
{
Pattern regexSplit = Pattern.compile(">");
Pattern proteinPattern = Pattern.compile("(.*?)([A-Z]{5,})");
Matcher m;
Scanner s = new Scanner(br);
s.useDelimiter(regexSplit);
while (s.hasNext())
{
StringBuffer sb = new StringBuffer();
String protein = s.next();
m = proteinPattern.matcher(protein);
if (m.find())
sb.append(m.group(2)).reverse().append(">r-").insert(0, m.group(1));
else
sb.append(protein);
);
}
bw.flush();
bw.close();
}
一些優化建議:
總是最好與探查器一起運行,並查看正在消耗時間而不是猜測的時間。 例如,可以通過增加程序的內存或避免某些慢的文件系統等來提高性能。
您不需要功能更強大的正則表達式,只需簡化流程即可,這樣就不必一遍又一遍地處理相同的文本。 在大多數情況下,這意味着使用Java的較低級別的regex API,即appendReplacement()
和appendTail()
。 通過將一個空字符串傳遞給appendReplacement()
我避免了它對后向引用的自動處理。
注意我也是如何使用find()
。 如果你發現自己在調用find()
(或matches()
或lookingAt()
並沒有檢查它的返回值,你做錯了什么。 這樣您才能知道比賽是否成功。
public static void main(String[] args) throws Exception
{
// this I/O code is bare-bones so as not to distract from the fun stuff
BufferedWriter bw = new BufferedWriter(new FileWriter("test_out.txt"));
// I use a lookahead so the ">" doesn't get discarded
Scanner sc = new Scanner(new File("test.txt")).useDelimiter("(?=>)");
while (sc.hasNext())
{
bw.write(reverseCapBlocks(sc.next()));
}
sc.close();
bw.close();
}
// cache these because recompiling them is fairly expensive
static final Pattern CAPS_PATTERN = Pattern.compile("\\b[A-Z]{5,}\\b");
static final Pattern BRACKET_PATTERN = Pattern.compile("^>");
static String reverseCapBlocks(String s)
{
StringBuffer sb = new StringBuffer();
Matcher m = CAPS_PATTERN.matcher(s);
while (m.find())
{
// appends whatever was between the last match and this one
// but hole off on appending the current match
m.appendReplacement(sb, "");
String temp = m.group();
// do the reversing manually because it's trivial and it avoids
// creating a new StringBuilder every time
for (int i = temp.length() - 1; i >= 0; i--)
{
sb.append(temp.charAt(i));
}
}
// append whatever was left after the last match
m.appendTail(sb);
// if the chunk began with ">", add the "r-"
return BRACKET_PATTERN.matcher(sb).replaceFirst(">r-");
}
我使用StringBuffer而不是StringBuilder,因為這是API所要求的,但這並不重要。 關於StringBuffer的低效率的報告雖然是正確的,但往往會被誇大。
正如我在評論中提到的那樣,您不應將整個文件加載到內存中。 這將導致內存換入和換出,並使程序變慢。
如果“蛋白質”的大小(即>
定界的字符串)在內存中是可管理的,則應采取措施
Scanner scanner = null;
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter("output.txt"));
scanner = new Scanner(new BufferedReader(new FileReader("input.txt")));
scanner.useDelimiter(">");
while ( scanner.hasNext() ) {
doReverseAndWriteToFile(scanner.next(), writer);
}
} finally {
if ( scanner != null) {
scanner.close();
}
if ( writer != null ) {
writer.flush();
writer.close();
}
}
在doReverseAndWriteToFile()
,應將程序的第二部分放在其中(我不太注意:-))。 在執行此功能時,還應繼續進行操作以寫入新文件。
如果使用此功能,一次只能在內存中存儲“ bufferSize” +“一種蛋白質的長度”。
看看是否可以加快速度。.否則,您必須尋找其他地方。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.