2009-02-25 13 views
60

मुझे कई लाइनों को फैलाने वाले टेक्स्ट के विरुद्ध मिलान करते समय पाइथन रेगेक्स को काम करने में कुछ परेशानी हो रही है। 'Some_Varying_TEXT' हिस्सा है, और बड़े पाठ कि यह नीचे दो पंक्तियों आता है की तर्ज के सभी: उदाहरण के लिए पाठ ('\ n' एक नई पंक्ति है)पाठ की एक बहुपक्षीय ब्लॉक से मेल खाने वाली नियमित अभिव्यक्ति

some Varying TEXT\n 
\n 
DSJFKDAFJKDAFJDSAKFJADSFLKDLAFKDSAF\n 
[more of the above, ending with a newline]\n 
[yep, there is a variable number of lines here]\n 
\n 
(repeat the above a few hundred times). 

मैं दो बातों पर कब्जा करना चाहते हैं एक कैप्चर (मैं बाद में न्यूलाइन अक्षरों को बाहर कर सकता हूं)। मैं कुछ दृष्टिकोण के साथ की कोशिश की है:

re.compile(r"^>(\w+)$$([.$]+)^$", re.MULTILINE) # try to capture both parts 
re.compile(r"(^[^>][\w\s]+)$", re.MULTILINE|re.DOTALL) # just textlines 

और कोई भाग्य के साथ करने के लिए जिसमें विविधताओं का एक बहुत। आखिरी वाला एक पाठ की पंक्तियों को एक-एक करके मेल खाता है, जो कि मैं वास्तव में नहीं चाहता हूं। मैं पहले भाग को पकड़ सकता हूं, कोई समस्या नहीं, लेकिन मुझे अपरकेस टेक्स्ट की 4-5 लाइनों को पकड़ने की प्रतीत नहीं होती है। मुझे मैच.group (1) कुछ _ होना चाहिए _ टेक्स्ट और समूह (2) लाइन 1 + लाइन 2 + लाइन 3 + आदि होने के लिए खाली लाइन का सामना करना पड़ेगा।

यदि कोई उत्सुक है, तो यह प्रोटीन बनाने वाले एमिनोसिड का अनुक्रम माना जाता है।

+0

वहाँ पहली पंक्ति और अपरकेस पाठ के अलावा फाइल में कुछ और है? मुझे यकीन है कि तुम क्यों बजाय न्यू लाइन पात्रों पर सभी पाठ बंटवारे और "some_Varying_TEXT" के रूप में पहला तत्व लेने का एक regex का प्रयोग करेंगे नहीं हूँ। – UncleZeiv

+2

हां, रेगेक्स इसके लिए गलत उपकरण है। – hop

+0

आपके नमूना पाठ में अग्रणी '>' वर्ण नहीं है। इसे होना चाहिए? – MiniQuark

उत्तर

81

इस प्रयास करें:

re.compile(r"^(.+)\n((?:\n.+)+)", re.MULTILINE) 

मुझे लगता है कि तुम्हारी सबसे बड़ी समस्या यह है कि आप linefeeds मैच के लिए ^ और $ एंकर की उम्मीद कर रहे है, लेकिन वे नहीं है। बहु मोड में, ^ स्थिति तुरंत निम्नलिखित एक नई पंक्ति और $ से मेल खाता स्थिति तुरंत एक नई पंक्ति पूर्ववर्ती मेल खाता है।

यह भी ध्यान रखें कि एक नई लाइन में एक लाइनफेड (\ n), एक कैरिज-रिटर्न (\ r), या कैरिज-रिटर्न + लाइनफीड (\ r \ n) शामिल हो सकता है। आप निश्चित नहीं है कि अपने लक्ष्य पाठ केवल linefeeds का उपयोग करता है, तो आप regex के इस अधिक समावेशी संस्करण का उपयोग करना चाहिए:

re.compile(r"^(.+)(?:\n|\r\n?)((?:(?:\n|\r\n?).+)+)", re.MULTILINE) 

BTW, आप यहाँ DOTALL संशोधक का उपयोग नहीं करना चाहते हैं; आप तथ्य यह है कि डॉट नई-पंक्तियों के अलावा सब कुछ से मेल खाता है पर भरोसा कर रहे हैं।

+0

यदि आप इस नियमित अभिव्यक्ति को रिक्त दूसरी पंक्ति वाले किसी भी टेक्स्ट फ़ाइल से मिलान करने के लिए नहीं चाहते हैं तो आप रेगेक्स में दूसरे डॉट को [ए-जेड] से बदलना चाहेंगे। ;-) – MiniQuark

+0

मेरी धारणा यह है कि लक्ष्य फ़ाइलें रिक्त बनाम गैर-खाली रेखाओं के एक निश्चित (और दोहराव) पैटर्न के अनुरूप होंगी, इसलिए [एजेड] निर्दिष्ट करना आवश्यक नहीं होना चाहिए, लेकिन शायद यह चोट नहीं पहुंचाएगा , या तो। –

+0

यह समाधान खूबसूरती से काम किया। एक तरफ, मैं क्षमा चाहता हूं, क्योंकि मैंने स्पष्ट रूप से पर्याप्त स्थिति को स्पष्ट नहीं किया है (और इस उत्तर की लापरवाही के लिए भी)। आपकी सहायताके लिए धन्यवाद! – Jan

1

खोज:

^>([^\n\r]+)[\n\r]([A-Z\n\r]+) 

\ 1 = some_varying_text

\ 2 = तो सभी अक्षरों की तर्ज

संपादित करें (सबूत है कि यह काम करता है):

text = """> some_Varying_TEXT 

DSJFKDAFJKDAFJDSAKFJADSFLKDLAFKDSAF 
GATACAACATAGGATACA 
GGGGGAAAAAAAATTTTTTTTT 
CCCCAAAA 

> some_Varying_TEXT2 

DJASDFHKJFHKSDHF 
HHASGDFTERYTERE 
GAGAGAGAGAG 
PPPPPAAAAAAAAAAAAAAAP 
""" 

import re 

regex = re.compile(r'^>([^\n\r]+)[\n\r]([A-Z\n\r]+)', re.MULTILINE) 
matches = [m.groups() for m in regex.finditer(text)] 

for m in matches: 
    print 'Name: %s\nSequence:%s' % (m[0], m[1]) 
+0

मुझे गलत लगता है। क्या आपने इसका परीक्षण किया? – Triptych

+0

ऐसा करता है, मैंने आपके लिए कुछ कोड जोड़ा है। –

+0

दुर्भाग्यवश, यह नियमित अभिव्यक्ति खाली रेखाओं से अलग पूंजी अक्षरों के समूहों से मेल खाती है। हालांकि यह एक बड़ा सौदा नहीं हो सकता है। – MiniQuark

14

यह काम करेगा:

>>> import re 
>>> rx_sequence=re.compile(r"^(.+?)\n\n((?:[A-Z]+\n)+)",re.MULTILINE) 
>>> rx_blanks=re.compile(r"\W+") # to remove blanks and newlines 
>>> text="""Some varying text1 
... 
... AAABBBBBBCCCCCCDDDDDDD 
... EEEEEEEFFFFFFFFGGGGGGG 
... HHHHHHIIIIIJJJJJJJKKKK 
... 
... Some varying text 2 
... 
... LLLLLMMMMMMNNNNNNNOOOO 
... PPPPPPPQQQQQQRRRRRRSSS 
... TTTTTUUUUUVVVVVVWWWWWW 
... """ 
>>> for match in rx_sequence.finditer(text): 
... title, sequence = match.groups() 
... title = title.strip() 
... sequence = rx_blanks.sub("",sequence) 
... print "Title:",title 
... print "Sequence:",sequence 
... print 
... 
Title: Some varying text1 
Sequence: AAABBBBBBCCCCCCDDDDDDDEEEEEEEFFFFFFFFGGGGGGGHHHHHHIIIIIJJJJJJJKKKK 

Title: Some varying text 2 
Sequence: LLLLLMMMMMMNNNNNNNOOOOPPPPPPPQQQQQQRRRRRRSSSTTTTTUUUUUVVVVVVWWWWWW 

इस नियमित अभिव्यक्ति के बारे में कुछ स्पष्टीकरण उपयोगी हो सकता है: ^(.+?)\n\n((?:[A-Z]+\n)+)

  • पहले वर्ण (^) का अर्थ है "एक पंक्ति के आरंभ में शुरू होने वाले"। ध्यान रखें कि यह नई लाइन से मेल नहीं खाता है ($ के लिए भी: इसका मतलब है "केवल एक नई लाइन से पहले", लेकिन यह नई लाइन से मेल नहीं खाता है)।
  • फिर (.+?)\n\n का अर्थ है "जितना संभव हो सके उतने पात्रों से मिलान करें (सभी पात्रों की अनुमति है) जब तक आप दो न्यूलाइन तक नहीं पहुंच जाते"। परिणाम (न्यूलाइन के बिना) पहले समूह में रखा जाता है।
  • [A-Z]+\n का अर्थ है "जब तक आप एक नई पंक्ति तक पहुंच सकें जो मैच के रूप में कई अपर केस अक्षर। यह परिभाषित करता है क्या मैं एक textline कॉल करेंगे।
  • ((?:textline)+) का मतलब मैच एक या अधिक textlines लेकिन नहीं है एक समूह में प्रत्येक पंक्ति डाल दिया। इसके बजाय, सभीtextlines एक समूह में डाल दिया।
  • आप नियमित अभिव्यक्ति में एक अंतिम \n जोड़ सकता है कि आप एक डबल न्यू लाइन लागू करना चाहते हैं अतं मै।इसके अलावा
  • , यदि आप के बारे में न्यू लाइन आप किस प्रकार (\n या \r या \r\n) तो बस (?:\n|\r\n?) द्वारा \n के हर घटना की जगह नियमित अभिव्यक्ति ठीक हो जाएगा सुनिश्चित नहीं हैं।
+0

मैच() लक्ष्य टेक्स्ट की शुरुआत में ही एक मैच लौटाता है, लेकिन ओपी ने कहा कि प्रति फ़ाइल सैकड़ों मैच होंगे। मुझे लगता है कि आप इसके बजाय खोजक() चाहते हैं। –

+1

@Alan: बस ठीक है, धन्यवाद। – MiniQuark

1

मेरी प्राथमिकता।

lineIter= iter(aFile) 
for line in lineIter: 
    if line.startswith(">"): 
     someVaryingText= line 
     break 
assert len(lineIter.next().strip()) == 0 
acids= [] 
for line in lineIter: 
    if len(line.strip()) == 0: 
     break 
    acids.append(line) 
इस बिंदु आप एक स्ट्रिंग, और स्ट्रिंग की एक सूची के रूप में एसिड के रूप में someVaryingText है पर

। आप किसी एकल स्ट्रिंग बनाने के लिए "".join(acids) कर सकते हैं।

मैं इस कम निराशा (और अधिक लचीला) की तुलना में बहु regexes पाते हैं।

4

प्रत्येक फ़ाइल केवल aminoacids में से एक अनुक्रम है, तो मैं सभी को एक रेगुलर एक्सप्रेशन का उपयोग नहीं होता। बस कुछ इस तरह:

def read_amino_acid_sequence(path): 
    with open(path) as sequence_file: 
     title = sequence_file.readline() # read 1st line 
     aminoacid_sequence = sequence_file.read() # read the rest 

    # some cleanup, if necessary 
    title = title.strip() # remove trailing white spaces and newline 
    aminoacid_sequence = aminoacid_sequence.replace(" ","").replace("\n","") 
    return title, aminoacid_sequence 
+0

यदि कुछ और तर्क जोड़ा गया है तो निश्चित रूप से सबसे आसान तरीका है, और यह भी अधिक काम करने योग्य है। यद्यपि इस विशिष्ट डेटासेट में लगभग 885 प्रोटीन हैं, और मुझे लगा कि एक रेगेक्स इसे संभालने में सक्षम होना चाहिए। – Jan

संबंधित मुद्दे

 संबंधित मुद्दे