[python] Detekce kodovani zadaneho vstupu (bylo RE: soubor v jiné zankové sadě)

Petr Prikryl PrikrylP na skil.cz
Pátek Září 30 09:14:19 CEST 2005


Navrhuji další úpravu "mazacího" skriptu...

Ve funkci smazat se konverze na unicode provádí dvakrát: 

geon...
>
> def smazat(cesta):
>     print os.listdir(cesta)
>     print unicode(cesta,"cp1250"), "---> OPRAVDU SMAZAT? (a/n): ",
>     ano=raw_input()
>     if ano.lower()!='a':
>         return False
>     for root, dirs, files in os.walk(unicode(cesta,"cp1250"), topdown=False):
>         for file in files:
>             soubor=os.path.join(root, file)
>             os.chmod(soubor,stat.S_IWRITE)
>             os.remove(soubor)
>         if root != cesta:  # mazani adresaru krome toho zadaneho...
>             os.chmod(root,stat.S_IWRITE)
>             print root
>             os.rmdir(root)
>     return True

Dalo by se to sice udělat jednou (trošku se to zpřehlední).
Kromě toho bych upravil test na "ano" (první písmeno 
zadaného řetězce se porovnává s více možnostmi):

def smazat2(cesta):
    cesta = unicode(cesta, 'cp1250')
    print os.listdir(cesta)
    print cesta, "---> OPRAVDU SMAZAT? (a/n): ",
    odpoved=raw_input()[0]
    if odpoved not in 'aAyY':
        return False
    for root, dirs, files in os.walk(cesta, topdown=False):
        for file in files:
            soubor=os.path.join(root, file)
            os.chmod(soubor,stat.S_IWRITE)
            os.remove(soubor)
        if root != cesta:  # mazaní adresaru krome toho zadaneho...
            os.chmod(root,stat.S_IWRITE)
            print root
            os.rmdir(root)
    return True

Jenže tohle nebude fungovat z DOSového okna (kódování
cp852 -- viz dále). Doporučuji upravit funkci smazat()
tak, aby se cesta přímo z venku zadávala v unicode. 
To znamená, že funkce pouze ověří, že tomu tak je:

def smazat3(cesta):
    assert(isinstance(cesta, unicode))
    print os.listdir(cesta)
    print cesta, "---> OPRAVDU SMAZAT? (a/n): ",
    odpoved=raw_input()[0]
    if odpoved not in 'aAyY':
        return False
    for root, dirs, files in os.walk(cesta, topdown=False):
        for file in files:
            soubor=os.path.join(root, file)
            os.chmod(soubor,stat.S_IWRITE)
            os.remove(soubor)
        if root != cesta:  # mazaní adresaru krome toho zadaneho...
            os.chmod(root,stat.S_IWRITE)
            print root
            os.rmdir(root)
    return True

Převod na unicode se pak udělá před voláním smazat3(), 
protože to logicky patří mimo tuto funkci.

Kdysi mě velmi hnětlo, že jsem musel moduly používající
raw_input() přizpůsobovat tomu, jestli je spouštím
prostřednictvím nějakého windowsovského okna, nebo 
prostřednictvím DOSového okna. Nelíbilo se mi, že
někde musím při konverzi do unicode psát natvrdo 
'cp1250' (z DOSového okna se používá jiné kódování,
než ve windowsovém okně -- např. v konzole IDLE). 
Jenže zrovna v tomto případě to jde udělat šikovněji.
Tahle informace je ukryta pod sys.stdin.encoding.


Příklad v DOS:

>>> import sys
>>> sys.stdin.encoding
'cp852'

Příklad v IDLE:

>>> import sys
>>> sys.stdin.encoding
'cp1250'

To znamená, že toho můžu využívat při načítání 
cesty (před voláním smazat3()) a skript bude 
fungovat jak z dosového okna, tak z windowsového.
Nikde se v něm nevyskytuje 'cp1250' nebo něco 
podobného (definice použitého kódování v hlavičce
souboru s tím nesouvisí, tu nepočítám):

def main():
    print 'Zadej cestu:',
    cesta = unicode(raw_input(), sys.stdin.encoding)
    smazat3(cesta)
    

if __name__ == '__main__':
    main()


pepr

-- 
Petr Prikryl (prikrylp at skil dot cz) 



Další informace o konferenci Python