Sunday, August 16, 2015

თავი 11,3



11.3 Combining searching and extracting


თუ გვინდა, რომ ხაზში რომელიც იწყება “X- - ით ვიპოვნოთ ნომრები, როგორიცაა:

X-DSPAM-Confidence: 0.8475
X-DSPAM-Probability: 0.0000

ჩვენ არ გვინდა უბრალოდ მცურავწერტილიანი ნომრები ნებისმიერი ხაზიდან. ჩვენ ვიღებთ მხოლოდ იმ ნომრებს იმ ხაზებიდან, რომელსაც აქვს ზემოთ მოყვანილი სინტაქსი.

შეგვიძლია გავაკეთოთ შემდეგი რეგულარული გამოსახულება ხაზის მოსანიშნად:

ˆX-.*: [0-9.]+


თარგმანი: ვამბობთ რომ გვინდა ხაზები რომელიც იწყება “X-” - ით და მოყვება ნული ან მეტი სიმბოლო .* შემდეგ ორწერტილი(„:“) და შემდეგ ჰარი. ჰარის შემდეგ ვეძებთ ერთ ან მეტ სიმბოლოს, რომელიცაა მთელი რიცხვი ან წერტილი „[0-9.]+“ . შენიშვნა: კვადრატულ ფრჩხილებს შორის წერტილი არის ნამდვილი წერტილი და არა wildcard.
ეს არის ძალიან მჭიდრო გამოსახულება, რომელიც დაემთხვევა მხოლოდ იმ ხაზებს, რაც გვაინტერესებს:


import re
hand = open( ' mbox-short.txt ' )
for line in hand:
line = line.rstrip()
if re.search( ' ˆX\S*: [0-9.]+ ' , line) :
print line


პროგრამას როცა გავუშვებთ ვნახავთ გაფილტრულ მონაცემებს მხოლოდ იმ ხაზებით, რასაც ვეძებდით.


X-DSPAM-Confidence: 0.8475
X-DSPAM-Probability: 0.0000
X-DSPAM-Confidence: 0.6178
X-DSPAM-Probability: 0.0000

მაგრამ ეხლა გვაქვს გადასაჭრელი პრობლემა - ამოვიღოთ ციფრები split - ის გამოყენებით.
მიუხედავად იმისა, რომ split - ის გამოყენება იქნება საკმაოდ მარტივი, ჩვენ შეგვიძლია გამოვიყენოთ რეგულარული გამოსახულებების კიდევ ერთი თვისება - ძებნა და გარჩევა ერთდროულად.

რეგულარულ გამოსახულებაში ფრჩხილებიც სპეციალური სიმბოლოა. რეგულარული გამოსახულებას ფრჩხილებს როცა ამატებ, ისინი იგნორირებულია სტრინგის დამთხვევისას, მაგრამ როცა იყენებ findall() - ს, ფრჩხილები აჩვენებს, რომ სანამ გინდა მთლიანი გამოსახულების დამთხვევა, დაინტერესებული ხარ, რომ ამოიღო ქვესტრინგის მხოლოდ ერთი ნაწილი - რომელიც ემთხვევა რეგულარულ გამოსახულებას.
პროგრამა შევცვალეთ ასე:

import re
hand = open( ' mbox-short.txt ' )
for line in hand:
line = line.rstrip()
x = re.findall( ' ˆX\S*: ([0-9.]+) ' , line)
if len(x) > 0 :
print x

search() - ის გამოძახების ნაცვლად, დავამატეთ ფრჩხილები რეგულარული გამოსახულების იმ ნაწილს, რომელიც წარმოადგენს წილად ციფრს იმის საჩვენებლად, რომ გვინდა მხოლოდ findall(), რომ მოგვცეს წილადი ციფრის ნაწილი დამთხვეული სტრინგიდან.
პროგრამის ამონაბეჭდია შემდეგი:

[ ' 0.8475 ' ]
[ ' 0.0000 ' ]
[ ' 0.6178 ' ]
[ ' 0.0000 ' ]
[ ' 0.6961 ' ]
[ ' 0.0000 ' ]
..


ციფრები ჯერ ისევ მოცემულია სიაში და საჭიროა გარდაქმნა სტრინგიდან წილადად,
სხვა მაგალითი ამ ტექნიკის:  http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772

თუ გვენდომებოდა რომ ამოგვეღო ყველა revision numbers (მთელი რიცხვები ხაზების ბოლოდან) იგივე ტექნიკის გამოყენებით რაც ზემოთ გამოვიყენეთ, უნდა დაგვეწერა შემდეგი პროგრამა:

import re
hand = open( ' mbox-short.txt ' )
for line in hand:
line = line.rstrip()
x = re.findall('ˆDetails:.*rev=([0-9.]+)', line)
if len(x) > 0:
print x

ჩვენი პროგრამის თარგმანი: ვეძებთ ხაზებს რომელიც იწყება „Details - ით“, რასაც მოყვება მებისმიერი რაოდენობის სიმბოლოები “.*” შემდეგ „rev=“ და შემდეგ ერთი ან მეტი მთელი რიცხვი. ჩვენ გვინდა ხაზები რომელიც ემთხვევა მთლიან გამოსახულებას, მაგრამ გვინდა, რომ ამოვიღოთ მხოლოდ მთელი რიცხვები ხაზის ბოლოდან, ამიტომ [0-9.]+ ჩავსვით ფრჩხილებში. პროგრამის ამონაბეჭდი იქნება:

[ ' 39772 ' ]
[ ' 39771 ' ]
[ ' 39770 ' ]
[ ' 39769 ' ]
...

დაიმახსოვრე რომ „[0-9.]+“ არის „ხარბი“  და სანამ ციფრებს ამოიღებს მანამდე ეცდება გააკეთოს მთელი რიცხვების რაც შეიძლება დიდი სტრინგი. ამ „ხარბი“ ქცევის გამო ვიღებთ ყველა ციფრს.  რეგულარული გამოსახულების ბიბლიოთეკა ვრცელდება ორივე მიმართულებით, სანამ ნახავს არა-რიცხვს ხაზის დასაწყისში ან ბოლოში.
ახლა შეგვიძლია გამოვიყენოთ რეგულარული გამოსახულება რომ ხელახლა გავაკეთოთ ძველი სავარჯიშო, რომელში გვაინტერესებდა დღის დრო ყოველი წერილიდან. ვეძებდით ხაზებს ამ ფორმით:

From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008

და გვინდოდა ამოგვეღო საათი ყოველი ხაზიდან. ადრე ეს გავაკეთეთ split - ის ორი გამოძახებით. პირველად ხაზი გაიხლიჩა(split) სიტყვებად, შემდეგ ავიღეთ მეხუთე სიტყვა და ორწერტილების მიხედვით ისევ გავხლიჩეთ ორი სიმბოლოს ამოსაღებად.
მიუხედავად იმისა, რომ კოდი მუშაობს, ის მაინც არის საკმაოდ მყიფე. გათვლილი იმაზე,  რომ ხაზები ფორმატირებულია კარგად. თუ დაამატებ შეცდომების შემოწმებას ან (try/except - ის ბლოკს) თავის დასაზღვევად - რომ არასწორად ფორმატირებული ხაზების მიუხედავად  პროგრამა უშეცდომოდ იმუშაოს, კოდში იქნება 10 – 15 ძნელად წასაკითხი ხაზი.
რეგულარული გამოსახულებით ამის გაკეთება შეიძლება ბევრად მარტივად:

ˆFrom .* [0-9][0-9]:


გამოსახულების თარგმანი: ვეძებთ ხაზებს რომელიც იწყება „From  - ით“(შენიშვნა: ჰარი), რასაც მოყვება სიმბოლოები “.*” შემდეგ ჰარი, ორი მთელი რიცხვი „[0-9][0-9]“ და ორწერტილი. ესაა განსაზღვრება ხაზისა, რომელსაც ვეძებთ.
მხოლოდ საათის ამოსაღებად ვიყენებთ findall() - ს. მთელი რიცხვებს ვსვამთ ფრჩხილებში:

ˆFrom .* ([0-9][0-9]):

პროგრამა:

import re
hand = open( ' mbox-short.txt ' )
for line in hand:
line = line.rstrip()
x = re.findall( ' ˆFrom .* ([0-9][0-9]): ' , line)
if len(x) > 0 : print x


ამონაბეჭდი:

[ ' 09 ' ]
[ ' 18 ' ]
[ ' 16 ' ]
[ ' 15 ' ]
...