<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl">
	<id>http://brain.fuw.edu.pl/edu/index.php?action=history&amp;feed=atom&amp;title=%2FCw7</id>
	<title>/Cw7 - Historia wersji</title>
	<link rel="self" type="application/atom+xml" href="http://brain.fuw.edu.pl/edu/index.php?action=history&amp;feed=atom&amp;title=%2FCw7"/>
	<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=/Cw7&amp;action=history"/>
	<updated>2026-04-18T15:56:29Z</updated>
	<subtitle>Historia wersji tej strony wiki</subtitle>
	<generator>MediaWiki 1.34.1</generator>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=/Cw7&amp;diff=2047&amp;oldid=prev</id>
		<title>Jarekz: Utworzono nową stronę &quot;= TI:WTBD/Ćwiczenia 7 =  == Rozbiór archiwum poczty (listy dyskusyjnej) == zapisanego w postaci pojedynczego pliku (typu [http://en.wikipedia.org/wiki/Mbox ''mbox'...&quot;</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=/Cw7&amp;diff=2047&amp;oldid=prev"/>
		<updated>2015-05-23T15:00:02Z</updated>

		<summary type="html">&lt;p&gt;Utworzono nową stronę &amp;quot;= &lt;a href=&quot;/edu/index.php/TI:WTBD&quot; title=&quot;TI:WTBD&quot;&gt;TI:WTBD&lt;/a&gt;/Ćwiczenia 7 =  == Rozbiór archiwum poczty (listy dyskusyjnej) == zapisanego w postaci pojedynczego pliku (typu [http://en.wikipedia.org/wiki/Mbox &amp;#039;&amp;#039;mbox&amp;#039;...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nowa strona&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= [[TI:WTBD]]/Ćwiczenia 7 =&lt;br /&gt;
&lt;br /&gt;
== Rozbiór archiwum poczty (listy dyskusyjnej) ==&lt;br /&gt;
zapisanego w postaci pojedynczego pliku (typu [http://en.wikipedia.org/wiki/Mbox ''mbox'']) na poszczególne maile, a następnie -- każdego maila, na nagłówki i treść, za pomocą wyrażeń regularnych.&lt;br /&gt;
:Przykładowe dane można znaleźć np. w [http://mail.python.org/pipermail/python-list/ archiwum listy dyskusyjnej o Pythonie] -- pod ,,Downloadable version&amp;quot;.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
# coding: utf-8&lt;br /&gt;
# mailparse.py&lt;br /&gt;
&lt;br /&gt;
import re&lt;br /&gt;
mailsrx = re.compile(r'^From \S+ at .*\n$')&lt;br /&gt;
mbodyrx = re.compile(r'\n\n')&lt;br /&gt;
headsrx = re.compile(r'^([-\w]+): +((?:.|\n +)*)$', re.MULTILINE)&lt;br /&gt;
&lt;br /&gt;
def lines2mails(lines):&lt;br /&gt;
    '''wyciągamy linijka po linijce dopóki nie zbierze się z nich pełny mail,&lt;br /&gt;
    co poznamy gdy napotkamy linijkę separującą. Wtedy łączymy linijki &lt;br /&gt;
    w jeden string, i &amp;quot;ustępujemy&amp;quot; (yield).&lt;br /&gt;
        lines: iterator podający kolejne linijki&lt;br /&gt;
        wynikiem jest generator kolejnych maili'''&lt;br /&gt;
&lt;br /&gt;
    l_out = list()&lt;br /&gt;
    for line in lines:&lt;br /&gt;
        if not mailsrx.match(line):&lt;br /&gt;
            l_out.append(line)&lt;br /&gt;
        elif l_out:&lt;br /&gt;
            yield ''.join(l_out)&lt;br /&gt;
            l_out = list()&lt;br /&gt;
    yield ''.join(l_out)&lt;br /&gt;
&lt;br /&gt;
def mailsplit(rawmail):&lt;br /&gt;
    '''rozdzielamy &amp;quot;surowy&amp;quot; mail na blok nagłówków i resztę.&lt;br /&gt;
    '''&lt;br /&gt;
    return tuple(mbodyrx.split(rawmail, maxsplit=1))&lt;br /&gt;
&lt;br /&gt;
def parsehead(head):&lt;br /&gt;
    '''analizujemy blok nagłówków na poszczególne nagłówki, tzn. dwójki &lt;br /&gt;
    (klucz, wartość).&lt;br /&gt;
    '''&lt;br /&gt;
    headers = headsrx.findall(head)&lt;br /&gt;
    return headers&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    '''żeby to wszystko przetestować analizujemy plik(i) wejściow(y|e)&lt;br /&gt;
    i wypisujemy dane z nagłówków 'From', 'Date' i 'Subject'.'''&lt;br /&gt;
&lt;br /&gt;
    from fileinput import input&lt;br /&gt;
&lt;br /&gt;
    rawmails = lines2mails(input())&lt;br /&gt;
    splitmails = (mailsplit(item) for item in rawmails)&lt;br /&gt;
    parsedmails = ((parsehead(head), body) for (head, body) in splitmails)&lt;br /&gt;
    for pm in parsedmails:&lt;br /&gt;
        headers, body = pm&lt;br /&gt;
        headers = dict(headers)&lt;br /&gt;
        print '{From}\t{Date}\t{Subject}'.format(**headers)&lt;br /&gt;
        &lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wykrywanie w plikach z kodem źródłowym w Pythonie instrukcji powodujących import modułów, ==&lt;br /&gt;
i sporządzenie na tej podstawie listy modułów, od których zależy dany kod.&lt;br /&gt;
:Może to być zaskakujące, ale zadania takiego nie da się zrealizować w 100 procentach. Weźmy pod uwagę np.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
'''&lt;br /&gt;
import re&lt;br /&gt;
'''&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
za pomocą ''jedynie'' technik opartych na wyrażeniach regularnych nie da się w pełni skutecznie rozpoznać, że ta instrukcja ''import'' jest częścią ''stałej napisowej'', a nie prawdziwą instrukcją. Mniejsza zresztą o teoretyczną niemożliwość, na pewno w praktyce jest to zbyt trudne -- trzeba wziąć pod uwagę, że w programie może występować wiele stałych napisowych, a więc trzeba liczyć otwarcia/zamknięcia cudzysłowów, w dodatku cudzysłowy różnych rodzajów wolno zagnieżdżać... Widać, że rozbiór składniowy (parsowanie) języków programowania (jak Python) nie może się opierać na technice wyrażeń regularnych. Na szczęście, interesują nas głównie pliki danych, których składnia ma większe szanse być (przynajmniej w przybliżeniu) ''regularna'', czyli możliwa do opanowania wyrażeniami regularnymi.&lt;br /&gt;
Inne przypadki sprawiające problemy to np.:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
if warunek: import re&lt;br /&gt;
&lt;br /&gt;
try: import foobar&lt;br /&gt;
except: pass&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Zwłaszcza ten pierwszy jest nie do opanowania: ''warunek'' może być bardzo złożonym wyrażeniem, z wielokrotnie zagnieżdżonymi nawiasami i cudzysłowami (stałe napisowe)! &lt;br /&gt;
Te ,,wyjątkowe&amp;quot; przypadki mają tyle ze sobą wspólnego, że są w praktyce ''rzadkie''. To znaczy, że mało kto w rzeczywistości tak pisze kod, a nikt tak pisać ''nie musi''. Możemy więc założyć, że analizujemy kod nie tylko poprawny składniowo (chyba jest już jasne, że poprawności składniowej kodu w Pythonie z zasadniczych powodów ''nie da się'' zweryfikować ''tylko'' za pomocą wyrażeń regularnych); ale w dodatku przestrzegający pewnych zasad ,,dobrego stylu&amp;quot;: np., że ''import'' wewnątrz instrukcji warunkowej zaczyna się od nowej linii; albo, że w stałej znakowej, linia zaczynająca się od słowa ''import'' powinna być ujęta w oddzielny cudzysłów. &lt;br /&gt;
Z tymi zastrzeżeniami, spróbujmy znaleźć rozwiązanie, które skutkuje jeśli za przykład testowy potraktować coś takiego jak poniżej:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from os import *&lt;br /&gt;
import sys&lt;br /&gt;
import string , re&lt;br /&gt;
import\&lt;br /&gt;
csv&lt;br /&gt;
#import lineinput # do not import&lt;br /&gt;
from os.path\&lt;br /&gt;
    import isfile, isdir&lt;br /&gt;
&lt;br /&gt;
def funkcja():&lt;br /&gt;
    import numpy as np&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
import numpy.random as rand, pylab&lt;br /&gt;
&lt;br /&gt;
# wynik powinien być: csv numpy numpy.random os os.path pylab re string sys&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
W szczególności należy wziąć pod uwagę, że pomiędzy jednostkami leksykalnymi (słowami) tworzącymi polecenie, wszędzie tam, gdzie wymagany jest odstęp (ciąg co najmniej 1 spacji/tabulacji), może on mieć również postać '\' plus bezpośrednio po ukośniku przejście do nowej linii.&lt;br /&gt;
Specyfikacja ogólnej postaci odstępu pomiędzy słowami może więc wyglądać tak: &amp;lt;code&amp;gt;(?:[ \t]|\\\n)+&amp;lt;/code&amp;gt; gdzie do grupowania wyrażeń użyłem &amp;lt;code&amp;gt;(?: ... )&amp;lt;/code&amp;gt; tworzącego grupę nieprzechwytującą (nie interesuje mnie, jakiej dokładnie postaci odstępu rozdzielającego użyto..). Ukośnik '\' musi być potrojony, by został potraktowany raz dosłownie, a drugi raz -- jako tworzący wraz z literą 'n' sekwencję reprezentującą kod nowej linii.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
# coding: utf-8&lt;br /&gt;
# findimports.py&lt;br /&gt;
&lt;br /&gt;
import re&lt;br /&gt;
&lt;br /&gt;
fromimportrx = re.compile(&lt;br /&gt;
                        r'^[ \t]*from'     # ewentualne wcięcie&lt;br /&gt;
                        r'(?:[ \t]|\\\n)+' # odstępy lub nowa linia z backslashem&lt;br /&gt;
                        r'(\w+(?:\.\w+)*)' # nazwa modułu&lt;br /&gt;
                        r'(?:[ \t]|\\\n)+' # znów odstępy itd.&lt;br /&gt;
                        r'import'          # dalej już nieważne co&lt;br /&gt;
                        , re.MULTILINE)&lt;br /&gt;
importrx = re.compile(&lt;br /&gt;
                    r'^[ \t]*import'&lt;br /&gt;
                    r'(?:[ \t]|\\\n)+'&lt;br /&gt;
                    r'((?:'&lt;br /&gt;
                    r'(?:\w+(?:\.\w+)*)' # nazwa modułu, ewent. słowo `as'&lt;br /&gt;
                    r'|(?:[ \t]|\\\n)'   # odstępy itd.&lt;br /&gt;
                    r'|,)+)' # ,p1.mod1 as alias1, mod2, p3 ...&lt;br /&gt;
                    , re.MULTILINE)&lt;br /&gt;
&lt;br /&gt;
importas = re.compile(&lt;br /&gt;
                    r'^(\w+(?:\.\w+)*)'  # nazwa&lt;br /&gt;
                    r'(?:'&lt;br /&gt;
                    r'(?:[ \t]|\\\n)+'&lt;br /&gt;
                    r'as'&lt;br /&gt;
                    r'(?:[ \t]|\\\n)+'&lt;br /&gt;
                    r'\w+'               # alias, nieważne jaki&lt;br /&gt;
                    r')?'&lt;br /&gt;
                    r'$')&lt;br /&gt;
&lt;br /&gt;
def find_imports(source):&lt;br /&gt;
    imports = set()&lt;br /&gt;
    found = importrx.findall(source)&lt;br /&gt;
    for s in found:&lt;br /&gt;
        imports |= set(importas.search(sss).group(1)&lt;br /&gt;
                        for sss in (&lt;br /&gt;
                            ss.strip() for ss in s.split(',')&lt;br /&gt;
                            )&lt;br /&gt;
                    )&lt;br /&gt;
    found = fromimportrx.findall(source)&lt;br /&gt;
    imports |= set(found)&lt;br /&gt;
    return imports&lt;br /&gt;
&lt;br /&gt;
def test():&lt;br /&gt;
    imports = find_imports(test_string)&lt;br /&gt;
    for item in sorted(imports):&lt;br /&gt;
        print item,&lt;br /&gt;
    print&lt;br /&gt;
&lt;br /&gt;
test_string = '''&lt;br /&gt;
from os import *&lt;br /&gt;
import sys&lt;br /&gt;
import string , re&lt;br /&gt;
import\&lt;br /&gt;
csv&lt;br /&gt;
#import lineinput # do not import&lt;br /&gt;
from os.path\&lt;br /&gt;
    import isfile, isdir&lt;br /&gt;
&lt;br /&gt;
def funkcja():&lt;br /&gt;
    import numpy as np&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
import numpy.random as rand, pylab&lt;br /&gt;
&lt;br /&gt;
# wynik powinien być: csv numpy numpy.random os os.path pylab re string sys&lt;br /&gt;
'''&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    from optparse import OptionParser&lt;br /&gt;
    parser = OptionParser()&lt;br /&gt;
    parser.add_option('-t', '--test', action='store_true', dest='test', default=False)&lt;br /&gt;
    parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False)&lt;br /&gt;
    opts, args = parser.parse_args()&lt;br /&gt;
    if opts.test:&lt;br /&gt;
        test()&lt;br /&gt;
        return&lt;br /&gt;
    imports = dict()&lt;br /&gt;
    for fname in args:&lt;br /&gt;
        imports[fname] = find_imports(open(fname).read())&lt;br /&gt;
    all_imports = set().union(*imports.values())&lt;br /&gt;
    if opts.verbose:&lt;br /&gt;
        print 'All imports:',&lt;br /&gt;
    for item in sorted(all_imports):&lt;br /&gt;
        print item,&lt;br /&gt;
    print&lt;br /&gt;
    if opts.verbose:&lt;br /&gt;
        for fname in args:&lt;br /&gt;
            print fname + ':',&lt;br /&gt;
            for item in sorted(imports[fname]):&lt;br /&gt;
                print item,&lt;br /&gt;
            print&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Do gromadzenia nazw importowanych modułów wykorzystuję zbiory, ponieważ nie interesuje mnie, ile razy który moduł był importowany, tylko '''czy''' był;&lt;br /&gt;
* polecenia postaci &amp;lt;code&amp;gt;import mod1, mod2 as alias, mod3...&amp;lt;/code&amp;gt; analizuję w dwóch etapach, za pomocą drugiego i trzeciego wyrażenia regularnego;&lt;br /&gt;
* opcja ''--verbose'' (równoważnie, ''-v'') powoduje wypisanie, oprócz listy nazw modułów importowanych we wszystkich plikach wymienionych na linii poleceń łącznie, list osobno dla poszczególnych plików.&lt;br /&gt;
* opcja ''re.MULTILINE'' (w funkcji ''re.compile'') służy temu, by ''^'' i ''$'' pasowały do początku i końca linii, a nie jedynie początku i końca całego napisu.&lt;br /&gt;
&lt;br /&gt;
''C.D.N.''&lt;/div&gt;</summary>
		<author><name>Jarekz</name></author>
		
	</entry>
</feed>