Zapisz jako PDF

Transkrypt

Zapisz jako PDF
TI:WTBD/Ćwiczenia 2
Tutaj zajęliśmy się trochę wykorzystaniem w programach argumentów wywołania przekazanych na
linii poleceń. Jest to odrobinę obok zasadniczego tematu, ale rzecz jest przydatna jeżeli chcemy
tworzyć narzędzia wielokrotnego użytku, nadające się do udostępnienia komuś innemu niż sam
autor.
Pierwszy przykład emuluje częściowo systemowe polecenie iconv (proszę zajrzeć do manuala).
Analizę argumentów wykonujemy "ręcznie", aby się przekonać, że nie jest to trudne. Identyfikujemy
opcje -f i -t jako poprzedzające nazwy kodowań: odpowiednio, początkowego i docelowego. Jeśli
którakolwiek z tych opcji nie wystąpi, to nie wiadomo co robić -- więc zgłaszamy błąd i kończymy.
Reszta argumentów to nazwy plików do przetworzenia. Wynik posyłamy jednym strumieniem na
standardowe wyjście.
#! /usr/bin/python
# -*- coding: utf-8 -*# convtxt0.py
from sys import argv, stdin, stdout, stderr
progname = argv.pop()
args, from_enc, to_enc = list(), None, None
while argv:
curr = argv.pop()
if curr == '-f':
from_enc = argv.pop()
elif curr == '-t':
to_enc = argv.pop()
else:
args.append(curr)
if not (from_enc and to_enc):
stderr.write((u'Użycie: %s -f from_enc -t to_enc [plik1 ...]\n' %
progname)
.encode('utf-8')
)
exit(1)
if args:
for f in args:
stdout.write(open(f).read().decode(from_enc).encode(to_enc))
else:
stdout.write(stdin.read().decode(from_enc).encode(to_enc))
Słabością tej implementacji jest słabo określone zachowanie, gdy któraś z opcji (-f czy -t) wystąpi w
linii poleceń więcej niż raz. Na zdrowy rozum, sens mają dwa rozwiązania: albo uznać to za błąd
wywołania, albo pozwolić by -f występowało wielokrotnie i stosowało się do plików, których nazwy
występują po tym wystąpieniu -f (czyli kolejne pojawienie się tej opcji "przełączałoby" kodowanie wg.
którego interpretowana jest zawartość, dla dalszych plików). Zastosowanie tego podejścia do -t nie
miałoby chyba wiele sensu, bo nie ma co mieszać kodowań w ramach jednego strumienia
wyjściowego -- więc wielokrotne -t powinno raczej być błędem.
A jak się zachowuje kod powyżej tak jak stoi? I jak go zmienić, by działał wg. powyższych założeń?
Można też inaczej: skorzystać z "gotowca" dostarczonego w bibliotece standardowej:
#! /usr/bin/python
# coding: utf-8
from sys import argv, stdin, stdout, stderr
from optparse import OptionParser
parser = OptionParser()
parser.add_option('-f', '--from', type='string', dest='from_enc')
parser.add_option('-t', '--to', type='string', dest='to_enc')
opts, args = parser.parse_args()
if not opts.from_enc or not opts.to_enc:
stderr.write(
(u'Wywołanie: %s [-f|--from] kodowanie1 [-t|--to] kodowanie2 [plik1
...]\n' % argv[])
.encode('utf-8')
)
exit(1)
if args:
for f in args:
stdout.write(open(f).read().decode(opts.from_enc).encode(opts.to_enc))
else:
stdout.write(stdin.read().decode(opts.from_enc).encode(opts.to_enc))
Nie jest to może dużo krótsze, i nie rozwiązuje problemu, o którym mowa powyżej, ale za to daje
obsługę tzw. długich nazw opcji (--from, ..), nieco większą elastyczność (dopuszcza parę wersji
podawania argumentów do opcji), jest też możliwość autogenerowania "helpu" składanego i ładnie
formatowanego z opisów, podawanych w wywołaniach add_option. Proszę znaleźć sposób zrobienia
tego w dokumentacji i zastosować do powyższego przykładu.
W kolejnym kroku nauczyliśmy się korzystać metody translate wartości napisowych, na przykładzie
programiku, który eliminuje "polskie litery" z danych tekstowych, wymieniając je na ich
nieakcentowane odpowiedniki:
#! /usr/bin/python
# coding: utf-8
_asciify_pl_tab = (u'ĄĆĘŁŃÓŚŻŹąćęłńóśżź', u'ACELNOSZZacelnoszz')
asciify_pl_tab = dict()
for a, b in zip(*_asciify_pl_tab):
asciify_pl_tab[ord(a)] = b
#print asciify_pl_tab
def test(ienc='utf-8', oenc='utf-8'):
import fileinput
from sys import stdout
for line in fileinput.input():
stdout.write(line.decode(ienc).translate(asciify_pl_tab).encode(oenc))
if __name__ == '__main__':
test()
"Tablicę" (naprawdę -- słownik) translacji można było oczywiście wprowadzić od razu w postaci
literalnego słownika, byłoby to jednak bardziej żmudne i chyba mniej czytelne.
Przy okazji dowiedzieliśmy się o module fileinput, który automatyzuje iterację po linijkach z całego
ciągu plików (a nie tylko z jednego).

Podobne dokumenty