2012年10月24日

【Linux】文字化けで解凍不能なZIPファイル用「uunzip」第6版リリース

 前稿でunzip-cp932の第4版をリリースして以来、末尾に記載したucode()関数を活用したバカチョンのunzipコマンドの作成に勤しんで来た。これ自体の動作確認は早々に録れていたのだが、ついでに、利用言語別の翻訳対応やらドキュメント整備やら、仕様拡張の度に修正している内に結構時間を費やしてしまった。でも、ドキュメント整備をしながら動作チェックを進めた結果、良くやってしまう、とんでもない凡ミスを公開することだけは避けることが出来た様には思う。

 ということで予告通り、今版より改名し、uunzipとさせて頂いた。命名の気持ちはUniversal UNZIPなのだが、実際は、Uno UNZIP、つまり、一つのUNZIPツールって所であることも確かなことなので取り敢えず中をとって「Uni UNZIP」の略ということにさせて頂くことにした。命名の最初の発想は、キー入力で楽したかっただけってことは内緒だ(笑)。

 仕様的には機能提供重視で曲がりなりにその目的達成させた為、未だ発展途上なものの、少なくとも日本国内の日本語中心のユーザなら、ZIPファイルをバカチョンで文字化け無く解凍頂けるものになったと思うし、その気になってくれた外国人ユーザーにも活用出来る程度の機能とドキュメント整備は出来たかな? と思う。まぁ、当方の英語力で書いたbroken engllishでは伝わらないことも多いだろうが、自分も判らない英語ドキュメントは実際に使って試てから理解している口なので、その気になってくれたら何とかなるものと思っている。
 後、足りていないものはinstallerの公開だが、それは、次稿で行ない、本稿のuunzipと合わせた配布パッケージを作成し、掲載しようと思っている。乞うご期待と言ったところだ。

 尚、使い方等は、ソース中のヘルプに入っているので改めて、本文に記載することは遠慮させてもらう。エスケープシーケンスの制御文字を含む為、多少見難いとは思うが、ご勘弁頂きたい。

            ~/uunzip.py (前半)


#!/usr/bin/python2.6
#-*- coding: utf-8 -*-
u"""
uunzip: UUNZIP(Uni UNZIP) unzips an zip arcive file that created with OS for any
language encoding. Default setup is for Japanese Language encodings. If
not worked well, Set encoding, encoding0 and enocdings option for your
language's encodings.

USAGE: uunzip <zip file> <path for extract files into> <target file1> <target file2> ...

※  Windows日本語版で作成したZIPファイルはアーカイブ情報の文字コードがcp932で
ある為、Linux上のツールによっては文字化けの為、解凍自体が出来ないことすらある。
 このソースコードはcp932をuncode化し問題解消図ったunzip-cp932を起源とするが、
今回、文字化け対策としてPython標準の全encodingを試す仕様にしたことから少なく
とも日本語利用中心の利用者間のZIPファイル交換なら、既定値のままで意識すること
なく双方向に解凍することが出来る筈だ。中文、ハングルと言った東アジア系
の言語圏のユーザであれば、変数encoding等をコマンドラインオプションで指定替え
することで同様に対応可能かと思う。但し、西欧言語には一切の配慮やテストもして
いないので、その成否は判らない。レポート頂けると有難いところだ。
 見た目はLinux標準のunzipに近い操作性をエミュレートしているが、unzip形式の
豊富なコマンドオプションは実装していない。引数位置は基本的に固定で、全てを
省略するか「--help」をつけると簡易ヘルプを、第1引数のZIPファイルのみを指定した
場合には、「unzip -l」相等の書庫情報リスト表示を解凍先ディレクトリ指定席の
第2引数を追加することで初めて主目的の解凍処理が機能する。さらに第3引数以降には
ZIP書庫内の解凍対象ファイルを必要なだけ個別で列記指定出来る。
 以上、機能的には少ないながらも「ヘルプ表示」「書庫一覧」「一括解凍」そして
「指定ファイルの書庫解凍」の4機能を提供出来ている。
 しかし、これだけでは日本語以外のユーザ環境では適切に対応出来ない可能性がある
のも事実なので、予め有用な既定値を与えている変数については「=」を挿み値を変更
出来る様にした。

【専用関数】
prn_help() : 簡易ヘルプ表示の関数
def unzip() : 個別ファイルの解凍先への解凍処理の本体
prn_ZipInfo() : 書庫情報の非表示
ZipInfo_sum(z) : 書庫情報の総ファイル長とファイル数のタプルを返す
exist_filename() : 拡張子補完を含め指定ファイル名の存否確認後存在名を返す
and_items() : 2つのリスト共通の文字列を返す関数(各要素は文字列に限る)
new_name() : 3桁の数値iを附記した非重複ファイル名候補を提示し入力
u_unzip() : 「uunzip(旧称:unzip-cp932)」の本体関数
main() : コマンド引数を処理しu-unzip()関数の引数を確定する関数
【汎用系関数】
select() : コンソールプロンプトを出し求める範囲の返答の英字1文字を返す
unicode_width() : UNICODE文字列の文字幅を返す関数(2010-05-10公開分)
unicode_ljust() : UNICODE左寄せ
unicode_center() : UNICODE中央寄せ
unicode_rjust() : UNICODE右寄せ
replaces() : 特殊文字をpython表記に置替える関数
"""
__author__ = "Mire in Japan"
__date__ = "2012-10-23"
__version__ = '0.0.6a'
__copyright__ = 'Copyright (c) 2012-09-28 Mire'
__license__ = 'GPL'
__url__ = 'http://pythonlife.seesaa.net/article/298750061.html '

__history__ = U"""【更新履歴】
0.0.1 2012-09-28  リリース初版
0.0.1a 2012-09-30  解凍処理中のみ個別ファイル名を画面表示する様に変更
0.0.2 2012-10-01  書出先に同名ファイルがある場合の処理選択を追加
オリジナルのunzipと異なりファイル名変更時に非重複名を
生成し提示する仕様に
 仕様変更部分の説明書きを修正
 ファイル名は引用符で囲んで表示する様に
0.0.3 2012-10-02  第3引数以降に解凍ファイル(複数)を指定出来る様に仕様変更
 さらに、第1引数だけのときは書庫情報の一覧を表示する様に
することで、解凍時には第2引数の解凍先の指定が必須となった。
0.0.4 2012-10-05  unzip-cp932の本体をunzip4cp932()関数に記述し、最下部の
実行部分はその引数定義に留めた。またunzip4cp932()関数はフロー
中心の記述に留め、具体的な処理は個別関数に記述した。
 また、オリジナルのunzipと異なり一覧表示時の項目幅も引数で
カスタマイズ可能にした。日本語化も変数のリテラル値を変更する
だけだ。
0.0.5 2012-10-06  ユニバーサルなunicode変換関数ucode()を適用、cp932に限らず
ZIP書庫情報の文字化けに対応した(つもり)。但し、既定では、現在
ucode()のencoding候補のencodingsには日本語関係のみ搭載。
[ 恒久的な別解としては、Python標準モジュールのzipfile.pyへの
patch作成もある。ここで充分テストした上で考えることにする。]
 zipとして読めないときのメッセージ表示を追加。
 このリリースより、名称をunzip-cp932からuunzipに変更。
0.0.6 2012-10-18  独自様式ながら、main()関数内定義の一部変数について、コマンド
オプションで、指定可能にした。u_unzip()関数にはuuzipの全機能を
main()関数は既定値の設定に加え、u_unzip()関数内のコマンド引数
の処理を移行、「味噌も○ ○ も」的色彩を薄めた。これにより、
encodingとencodingsを指定替えすることで多言語利用での「下手な
鉄砲も数打ちゃ中る」的精度と効率を上げることが取り敢えず可能に
なった。
0.0.6a 2012-10-23  ucode()関数のencoding名をPython内定義名称に統一し重複除去
Clean up source. edited documents of this help and functions.
enabled help customize with making help file. wrote on help
command options example.for other language users.
"""
__todo__ = u"""【TODO】: 対応する気はないけど(笑)備忘の為、課題を列記
*  オリジナルのunzipとは異なり、zip解凍の機能のみをpythonで実現したものだ。
従って、不具合解決や思いついた仕様を何時でも盛り込める。
*  ただ、unzip同等にコマンドとして実行するには、その為、Linux環境別に第1行目の
pythonへのpathを調整する必要がある。これは別途listallerで近日対応予定だ。
*  オリジナルのunzipとは異なり、unzipにある豊富なオプションには完全未対応。
これについては、強制上書等コマンド処理で有効なものはいずれ実現させる予定だ。
*  オリジナルのunzipとは異なり、第1引数のzipファイルのみを指定した場合は、
その書庫内のファイル一覧を表示する仕様としている。その為、解凍には第2引数の
「解凍先ディレクトリ」の指定が最低限必須となる仕様とした。
*  オリジナルのunzipとは異なり、第2引数は「解凍先ディレクトリ」の固定であり、
解凍対象ファイル名ではない。第3引数以降が解凍対象ファイルの指定席である。
*  現公開スタイルはBlogでのこのソースコードの表示公開のみだ。いくらLinux用と
言っても一般ユーザにはinstaller添付の配布パッケージが必要だろう。installerは
別途汎用で作成した上で、配布パッケージファイルを作成し近日DL可能にしたい。
"""

### 【専用関数】 ###
def read_help(file='uunzip.hlp'):
u"""
replace help_text function
"""
from os.path import exists
if exists(file):
fpi = open(file, 'r')
lines = fpi.readlines()
fpi.close()
help_txt = u''.join(lines)
return help_txt
else:
return None

def prn_help(pub_vanames=[], variables={}, help_txt=None):
u"""display help func.
簡易ヘルプ表示の関数
"""
if help_txt==None:
help_txt = u"""uunzip(unzip-cp932) %s of %s. Maintained by %s. Send bug
reports using %s
You can use uunzip(unzip-cp932 old name) and this source code under the terms of
the \'%s\' Licence.(See for detail: http://www.gnu.org/licenses/gpl.html )

USAGE: uunzip[ --help][ <a zip file>[ <path for extract files into>[ <file1> ...][ <valiable>=<value> ...]]]

1. Displays this.help.and values of public variables.
unnzip
or
unnzip --help

2. Displays files infomation list in zip file's archive.
uunzip <1.zipfile>

3. Extracts all archive files into specified path.
uunzip <1.zipfile> <2.path for extract files into>

4. Extracts specified file(s) into specified path.
uunzip <1.zipfile> <2. path for extract files into> <3.file1> <3.file2> ...

5. Specifies zip file's encoding.
uunzip <1> <2> <3> ... encoding='<zip file's encoding>'

6. Specifies zip files's encodings for your languages
uunzip <1> <2> <3> ... "encodings=['<encoding1>','<encoding2>'...]"

7. Transrates uunzip display. Please, transrate to your language.
uunzip <1> <2> <3> ... "answers=['y','n','A','N','r']"\\
msg_replace='\\rreplace \\"%%s\\"? [y]es, [n]o, [A]ll, [N]one, [r]ename: '\\
msg_zippath='\\rArchive: '\\
msg_new_name='\\rnew name[%%s]: '\\
msg_mkdir='\\rcreating: \\"%%s\\"'\\
msg_exit='\\r%%s was stoped.'\\
msg_skip='\\r\\"%%s\\" was skipped over.'\\
msg_unzip='\\rinflating: \\"%%s\\"'\\
msg_exists='uunzip: cannot find or open'\\
msg_readerr='Cannot read this file as zip.'\\
"zinfo_items=[u'Length ',u'Date',u'Time',u'Name']"\\
"zinfo_widths=[9,10,5,4]"\\
zinfo_files='files'\\
param='param'

8. Checks the value of variables spcified for customizing uunzip.
uunzip <1> <2> <3> ... <variable1>=<value> help=True

UUNZIP(Uni UNZIP) unzips an zip arcive file that created with OS for any
language encoding. Default setup is for Japanese Language encodings. If not
worked well, Set encoding, encoding0 and enocdings option for your language's
encodings. Command line option helps you to custamize for your zip archive files
created with Other Operation System.

Command line options of UUNZIP


See below for detail in Japanese.

詳細は下記参照(日本語のみ)

利用方法: uunzip[ --help][ <zipファイル>[ <解凍先ディレクトリ>[ <解凍対象ファイル1> ...][ <変数名>=<値> ...]]]

※ 書庫情報の表示には「ZIPファイル」1つを指定する。さらにZIP書庫内ファイルの
全解凍には「解凍先ディレクトリ」を続けて引数指定する。ZIP書庫内の特定ファイル
のみを解凍したい場合には、その後にそれらのファイル名を続けて引数指定する。
動作上の見栄えはunzipを模倣していているがコマンド式の多様なオプションは一切
実装していない。しかし以下の独自仕様で「文字コードの指定」「表示の日本語化」
を実現している。従って、よく使うオプションについては、Windowsであればbatch、
Linux系であれば、shellスクリプトに、その実行通り記述し、それを実行すれことで
容易にカスタマイズ出来る。uunzipは相応の蓋然性で多言語環境でも上手く文字化けを
回避するとは思うが、それが出来ない場合にはencoding、encoding0そしてencodingsに
以下の例示を参考に試して頂くと解決出来る可能性が高いものと思う。

unzip準拠表記を日本語に : lang (例、lang='ja')
ZIPファイルの文字コード : encoding (例、encoding='latin_1' )
手元PC OSの文字コード : encoding0 (例、encoding0='euc-kr' )
頻出文字コードの優先リスト: encodings (例、encodings=['gb18030','Big5'])
例(exapmles):
简体中文: "encodings=['cp950','big5hkscs','Big5','utf-8']"
繁體中文: "encodings=['gb18030','gbk','GB2312','Big5','hz','utf-8']"
한 국 어: "encodings=['cp949','utf-8','euc-kr','iso2022_kr','johab']"
西  欧: "encodings=['cp1250','mac_roman','cp1252','cp850','iso8859_15'
,'latin_1','utf-8','cp1140','cp500']"
※ 用途に合わせ要編集(Edit for your needs)
全encodingを試すか否か : test_all (例、test_all=True test_all=False)

 また、日本語化同様、他言語表示化も、以下の変数に対するコマンド引数を翻訳し、
適宜レイアウトを調整すれば概ね納得の行くだろう。
 以下に、オリジナルのunzip英語表記のコマンドオプション引数と日本語表記の例を
示しておくので、テキストエディタ上にコピペの上お好きな言語に翻訳した後に、
uunzup の後にコマンドオプションとして付けて実行して試てエラーにならず、正しく
「【変更可能な変数と現在値】」として表示されたら成功だ。必要によりencoding、
encodings及びencoding0辺りを上記のものを参考に適切に補完すれば、手持ちの殆どの
ZIPファイルが処理可能になるものと思う。文字列は全てunicode文字列であることが
必須で、スペース文字や引用符を含む場合に正しくOSに認識させるには含む引用符とは
異なる引用符で引数全体を囲む必要があることを忘れないで頂きたい。

"answers=['y','n','A','N','r']"\\
msg_replace='\\rreplace \\"%%s\\"? [y]es, [n]o, [A]ll, [N]one, [r]ename: '\\
msg_zippath='\\rArchive: '\\
msg_new_name='\\rnew name[%%s]: '\\
msg_mkdir='\\rcreating: \\"%%s\\"'\\
msg_exit='\\r%%s was stoped.'\\
msg_skip='\\r\\"%%s\\" was skipped over.'\\
msg_unzip='\\rinflating: \\"%%s\\"'\\
msg_exists='uunzip: cannot find or open'\\
msg_readerr='Cannot read this file as zip.'\\
"zinfo_items=[u'Length ',u'Date',u'Time',u'Name']"\\
"zinfo_widths=[9,10,5,4]"\\
zinfo_files='files'\\
param='param'

「lang='ja'」相当の翻訳でのコマンドオプション引数の例:

"answers=['y','n','A','N','r']"\\
msg_replace='\\r既存ファイル:\\"%%s\\"\\nこれを上書きしても宜しいのですか?\\nやる[y], 抜かす[n], 有る分全部上書き[A], 何もせず終了[N], 別名なら保管[r]: '\\
msg_zippath='\\r書庫ファイル: '\\
msg_new_name='\\r新たな名前[%%s]: '\\
msg_mkdir='\\r作成中: \\"%%s\\"'\\
msg_exit='\\r%%s は以降の処理を中止しました。'\\
msg_skip='\\r\\"%%s\\" を飛ばしました。'\\
msg_unzip='\\r解凍中: \\"%%s\\"'\\
msg_exists='uunzip: 探せないか開けません'\\
msg_readerr='ZIPとして読めません。\\nこれがZIPファイルなら再取得をお勧めします。'\\
"zinfo_items=[u'サイズ ',u'年-月-日',u'時:分',u'ファイル名']"\\
"zinfo_widths=[9,10,5,4]"\\
zinfo_files='件'\\
param='引数'

※ また逐一uunzip実行の度に、これらのコマンドオプションを手打ちやコピペするのは
非効率だ。確実なコマンドオプションの組合せが作成出来たなら、それをLinuxなら
シェルスクリプト、Windowsならバッチファイルにしてしまえば良いだろうし、他の
周辺ユーザにも提供したいなら、当方のBlogに連絡頂ければ適切な言語区分で機能する
様対処するつもりだ。

 同様に、このヘルプ文書(help_txt)も理論的には翻訳すれば同様の方法で可能かも
しれないが、引数で渡すにはあまりに大き過ぎるので、テキストファイル(help_file)
で指定出来る様にしている。このヘルプ文書の他言語訳または独自のヘルプ文書を書き
込んだファイルが、変数help_fileの示すパス存在すれば、そちらが優先表示される。

【コマンドオプションについて】
 以下の仕様で一部変数の既定値を変更可能です(変更可能な全変数は末尾を参照)。

<変数名>=<値> : 単一の整数、浮動小数点、論理値、None等
<変数名>='<値>' : 半角英数による文字列
<変数名>=u'<値>' : 日本語文字列等のUNICODE文字列
<変数名>=[<数値>, ...] : 数値の配列リスト
"<変数名>=['<値>', ...]" : 文字列の配列リスト
"<変数名>=[u'<値>', ...]" : UNICODE文字列の配列リスト

※ 蛇足ながら解凍後のファイル中の文字コード自体は当然圧縮時のままです。ファイル
の中身のコード変換は例えばnkf辺りがその守備範囲だ。そこ辺りを探って頂きたい。

【解凍先での上書きトラブル対応】
 また、解凍先に解凍ファイルと同じ名のファイルがある場合は、以下の様にその対応を
オリジナルのunzip同様、選択出来る様にしている。

%s

 [y]es : 上書きとする。※ 既存のファイルは復活出来ない。
 [n]o : 上書きしない。※ ファイルは既存のままで整合検査が必要なことも。
 [A]ll : 全てを上書き。※ 既存のファイルがあれば、それは復活出来ない。
 [N]one : 処理を中止。 ※ もう、何(None)もしません(笑)。
 [r]ename : 別名前で実行。※ オリジナルのunzipと異なり新ファイル名候補も提示。

 尚、「[r]ename」ではファイル名の末尾に数字を附加したファイル名を生成し候補と
して提示する。それで是なら改行、否ならCtrl+Shift+CとCtrl+Shift+Vでコピペする等
して、ファイル名入力し改行することになる。そうして、指定したファイル名が重複
していないなら解凍が実行され、不意の上書きは防止出来る。
 しかし、このuunzip(旧称unzip-cp932)には<解凍先ディレクトリ>を第2引数で指定
出来るので、一つでも「overwrire?:"<file>"」と表示されたなら[N]oneで何にもせず
処理を中止して、新たに新規の解凍先名を指定しuunzipを実行しZIPの中身全てを解凍
する方が推奨出来る。新規の解凍先名のフォルダは現存しないなら自動で作成し解凍が
なされるので手間は要らないし、テキストファイルならばlinuxの標準コマンドで
「diif -du <dir1> <dir2>」とすることで差分チェックも容易に出来るからだ。

【ライセンス】
 広く活用頂く為、GPLとしてます。GPLの日本語詳細は次のURL等で確認して下さい。
http://sourceforge.jp/projects/opensource/wiki/licenses%%252FGNU_General_Public_License_version_3.0

 このuunzipは%sライセンスの公開義務等に従いうことでこのソースコードも改変し
ご活用頂けます。その場合の改変内容の公開は不具合連絡同様、下記のBlogへの
コメントで済ませて下さる形で構いません。
%s

%s""" % (__version__, __date__, __author__, __url__, __license__
, ucode(variables['msg_replace'][1:] % ('<file>')), __license__, __url__
, __history__)

print help_txt

## 変更可能な変数名と値の一覧 ##
print u'【変更可能な変数と現在値】'
if variables['zip_name']: #第1引数=ZIPファイル名の値表示
print u'%s=zip : u\'%s\'' % (unicode_ljust('<%s1>' % \
(variables['param']), 8), variables['zip_name'])
else:
print u'%s=zip : None' % \
(unicode_ljust('<%s1>' % (variables['param']), 8))
if variables['dir']: #第2引数=解凍先ディレクトリの値表示
print u'%s=dir : u\'%s\'' % \
(unicode_ljust('<%s2>' % (variables['param']), 8), variables['dir'])
else:
print u'%s=dir : None' % \
(unicode_ljust('<%s2>' % (variables['param']), 8))
print u'%s=file:' % (unicode_ljust('<%s3>' % (variables['param']), 8)),
if (type(variables['selections']) is type(['list'])#第3引数=解凍指示書庫内ファイルの値表示
or type(variables['selections']) is type(('list'))):
#list、またはtupleなら、
s = u'[' # list形式で
v_list=[]
for i in variables['selections']: # list/tuple内変数値を1つずつ、
if type(i) is type('a'): # 文字列型なら、
v_list.append(u'\'%s\'' % ucode(i)) # 文字列表記で
elif type(i) is type(u'a'): # unicode文字列型なら、
v_list.append(u'u\'%s\'' % ucode(i))# unicode文字表記で
elif type(i) is type(1): # 整数型なら
v_list.append(u'%d' % (i)) # 整数として
elif type(i) is type(1.23): # 浮動小数点型なら、
v_list.append(u'%f' % (i)) # 浮動小数点として
elif type(i) is type(None): # Noneなら、
v_list.append(u'None') # Noneとして
elif type(i) is type(True): # Trueなら、
v_list.append(u'True') # Trueとして
elif type(i) is type(False): # Falseなら、
v_list.append(u'False') # Falseとしてv_listに貯込み
s += u','.join(v_list) # v_listをカンマでつなぎ追記
s += u']' # 括弧を閉じてから、
print s # 表示
else: #そうでないなら、
print variables['selections'] # Python標準出力で表示

vals = variables.keys() #変数名リストを作成し
vals.sort() #並べ替え
for v in vals: #それを1つずつ、
if v in pub_vanames: # 公開変数名の分だけ、
if v=='help_txt':
if variables[v]==None:
print u'%-13s: *** \'help_file\' not exists! ***' % (v)
else:
print u'%-13s: *** This help is loaded from help_file. ***' % (v)
elif type(variables[v]) is type('a'): # 文字列なら、
print u'%-13s: \'%s\'' % (v # 非表示の特殊文字を置替えた
, ucode(replaces(variables[v])))# unicode文字表記で表示
elif type(variables[v]) is type(u'a'): # UNICODE文字列なら、
print u'%-13s: u\'%s\'' % (v # 非表示の特殊文字を置替えた
, ucode(replaces(variables[v])))# unicode文字表記で表示
elif (type(variables[v]) is # list、またはtupleなら、
type(['list'])or type(variables[v]) is type(('list'))):
s = u'%-13s: [' % (v) # list形式で
v_list=[]
for i in variables[v]: # list/tuple内変数値を1つずつ、
if type(i) is type('a'): # 文字列型なら、
v_list.append(u'\'%s\'' % ucode(i))
# 文字列表記で
elif type(i) is type(u'a'): # unicode文字列型なら、
v_list.append(u'u\'%s\'' % ucode(i))
# unicode文字表記で
elif type(i) is type(1): # 整数型なら
v_list.append(u'%d' % (i)) # 整数として
elif type(i) is type(1.23): # 浮動小数点型なら、
v_list.append(u'%f' % (i)) # 浮動小数点として
elif type(i) is type(None): # Noneなら、
v_list.append(u'None') # Noneとして
elif type(i) is type(True): # Trueなら、
v_list.append(u'True') # Trueとして
elif type(i) is type(False): # Falseなら、
v_list.append(u'False') # Falseとしてv_listに貯込み
s += u','.join(v_list) # v_listをカンマでつなぎ追記
s += u']' # 括弧を閉じてから、
print s # 表示
else: # それ以外は
print u'%-13s: ' % (v), variables[v]# 変数名の後にpython既定表示

## 個別ファイルの解凍先への解凍処理本体 ##
def unzip(z #ZipFileオブジェクト
, unicode_name #unicode変換後のファイル名
, name #素のzip書庫内のファイル名
, filepath #zip書庫内ファイルの書出し先フルパス名
, msg_unzip=u'\rinflating: \"%s\"' #zip書庫内ファイルの解凍時のメッセージ
, bites=256): #書込み単位バイト数
u"""unzip a file from a zip file into filepath
個別ファイルの解凍先への解凍処理の本体関数、既存ファイル
の上書き判定でも同じ記述となるので冗長性解消の為に関数化
"""
print msg_unzip % (unicode_name)#解凍処理中の個別ファイル名を表示(2012-09-30)
#引用符で囲んで表示する様に変更(2012-10-01)
x = z.open(name, 'r') #ZIPファイル内の中身ファイルを開く
fpo = open(filepath, 'wb') #unicode文字列化したファイルの書込みを
d = x.read(bites) #ZIP内の個別ファイルを256biteずつ(既定)読取り
while d: #中身がある限り、ループ継続
fpo.write(d) # 解凍して行く
d = x.read(bites) # 次の256バイト(既定)を読取り、ループ折返し
x.close() #ZIPファイル内の中身ファイルを閉じる
fpo.close() #unicode文字列化したファイルを閉じる

def prn_ZipInfo(zip_name, encoding=None, encodings=[], test_all=False
, msg_zippath=u'\rfilepath:'
, zinfo_items = [u'Length ', u'Date', u'Time', u'Name'] #リスト項目名
, zinfo_widths = [9, 10, 5, 4] #リスト項目幅
, zinfo_line = u'-' #罫線用文字
, zinfo_files=u'files' #ファイル数の数詞
, msg_readerr=u'Cannot read this file as zip.' #zipとして読めないとき
):
u"""display archive infomation list in a zip file, such as 'unzip -l'
以下の様式の「unzip -l」相等の書庫情報一覧を表示する関数
既定値では以下の通り、
Length Date Time Name
--------- ---------- ----- ----
12345 2012-10-04 12:34 readme.txt
--------- -------
123456789 123 files
 但し、「unzip -l」の様にファイル長が9桁固定のままでは様式が壊れる可能性が
あるので、そこを自動調整可能な方向に仕様変更。2012-10-04
"""
from zipfile import ZipFile, BadZipfile #ZIP形式の圧縮ファイルの操作
t = zinfo_items
w = zinfo_widths
zinfo_size = u'%%%dd ' % (w[0])
print msg_zippath, zip_name #の引数を画面出力
# ZipFileオブジェクト生成 #
try:
z = ZipFile(zip_name, 'r') # 第1引数指定のZIPを読込モードで開き
except:
print msg_readerr # zipとして読めない旨表示し
return # prn_ZipInfo()を抜け
# (u_unzip()に戻りuunzip終端に)

sum , count = ZipInfo_sum(z) #総ファイルサイズ, ファイル総数
l = len('%d' % (sum)) #総ファイルサイズの表示文字数(幅)
max_len = max(w[0], l)
zinfo_header0 = u'%s %s %s %s' % (unicode_rjust(t[0], max_len)
, unicode_center(t[1], w[1]), unicode_ljust(t[2], w[2])
, t[3]) #項目名ヘッダー
zinfo_header1 = u'%s %s %s %s' % (''.ljust(max_len, '-')
, ''.ljust(w[1], '-'), ''.ljust(w[2], '-')
, ''.ljust(max(w[3], unicode_width(t[3])), '-'))
#罫線ヘッダー
cnt_str = u'%d %s' % (count, zinfo_files) #ファイル件数
zinfo_footer0=u'%s %s %s %s' % (''.ljust(max_len, '-')
, ''.ljust(w[1], ' '), ''.ljust(w[2], ' ')
, ''.ljust(unicode_width(cnt_str), '-'))
#罫線フッター
print zinfo_header0 #u' Length Date Time Name'
print zinfo_header1 #u'--------- ---------- ----- ----'
infolist = z.infolist() # 指定したZIPの書庫情報リストを取得
for info in infolist: # 書庫情報リストからファイル情報を順に取出し
print zinfo_size % (info.file_size) , # 解凍後のファイルサイズ
print u'%4d-%02d-%02d %02d:%02d' % ( # unzipでは「月-日-年」の順だか
info.date_time[:5]),# ISO準拠の「年-月-日」の仕様に
print u' \"%s\"' % ( # 空白文字を含むものをcopy&pasteする時に
ucode(info.filename, encoding, encodings, test_all))
# 有用な二重引用符囲みな仕様に
zinfo_footer1 = u'%%%dd %%s' % (w[0])
print zinfo_footer0 #u'--------- -------'
print zinfo_footer1 % (sum, cnt_str) #u'%9d %d files'

def ZipInfo_sum(z):
u"""total sizes of archive file infomation
書庫情報の総ファイル長とファイル数のタプルを返す関数
用途先: prn_ZipInfo()関数内のヘッダーとフッダーの項目幅決定で活用
"""
sum = 0 #解凍後の総ファイルサイズの初期化
infolist = z.infolist() #書庫情報リストを取得
for info in infolist: #そのリストから書庫情報を1つずつ
sum = sum + info.file_size # 解凍後の総ファイルサイズに加算
return sum, len(infolist) #総ファイル長とファイル数のタプルを返す

def exist_filename(filename #ファイルのフルパス名
, ext #補完する拡張子
, message='cannot find'): #ファイル不存在時のメッセージ
u"""file name exists in zip file archive
拡張子補完を含め、指定名のファイルの
存在を確認し在れば名前を返し無いなら
messageを表示した上でNoneを返す関数

uunzip: cannot find or open "abc.zip"
, "abc.zip.zip"
or "abc.zip.ZIP"
"""
from os.path import exists
f1 = '.'.join([filename, ext.lower()]) #第1引数+'.zip'
f2 = '.'.join([filename, ext.upper()]) #第1引数+'.ZIP'
if exists(filename): #第1引数が実在ファイルなら
return filename # 第1引数をZIPファイル名に
elif exists(f1): #第1引数+'.zip'が実在ファイルなら
return f1 # 第1引数+'.zip'をZIPファイル名に
elif exists(f2): #第1引数+'.ZIP'が実在ファイルなら
return f2 # 第1引数+'.ZIP'をZIPファイル名に
else: #第1引数のファイルは不存在なら
print message, # その旨表示して
l = unicode_width(message) # メッセージの文字長 ※全角半角未対応!!
print '\"%s\"' % (filename) # 比較したファイル名候補を
print '%s,' % (''.ljust(l-1)), # オリジナルのunzipにならい表示
print '\"%s\"' % (f1) #  但し、ファイル名の候補は比較し易い
print '%sor' % (''.ljust(l-2)), # 様に改行し頭を揃える様にした。
print '\"%s\"' % (f2) #
#exit() # ※ システム終了は、活用側記述とする
return None # Noneを返す

def and_items(list1, list0, encoding0, encoding, encodings, test_all):
u""" list of file names common to both lists of text into unicode
2つのリスト共通の文字列を返す関数(各要素は文字列に限る)
用途: 書庫情報list0と入力値list1で一致するリストの生成
"""
and_list=[] #解凍対象ファイル名のリスト
for item1 in list1: #順に
itm1 = ucode(item1, encoding0, encodings, test_all)
# 比較の為unicode文字列にしてから
i = 0
for item0 in list0: # ZIP内ファイル名一覧の中で
if itm1==ucode(item0, encoding, encodings, test_all):
# 解凍可能な完全一致の分は
and_list.append(item0) # 解凍対象ファイルリストに追加
exit # ループから抜ける
and_list = sorted(set(and_list), key=and_list.index)
return and_list #重複除去後のlistを返す

def new_name(wname, i=1, prompt=u'\rnew name[%s]: ', code='utf-8'):
u"""prompt with a file name candidate for rename
既存ファイル名と重複しない3桁の数値iを附記した候補の
ファイル名を提示した上で、ファイル名入力を促す関数
"""
from os.path import exists, splitext #ファイルの存否判定, 拡張子分離用
from sys import stdin #コマンドラインからの標準入力
root, ext = splitext(wname) #拡張子を分離し
fpath = wname #初期値には元々のファイル名をセットし
while exists(fpath): #生成文字列のファイルが存する限り、
fpath = '%s_%03d%s' % (root, i, ext)# 3桁数字附加のファイル名を生成
if exists(fpath): # 生成文字列のファイル存在なら
i += 1 # iを進め
else: # ファイルとして不存在なら
print prompt % (fpath), # それを候補として角括弧で表示し
fn = stdin.readline().strip() # ファイル名の手入力を促す
if not fn.strip()=='': # 入力があったら、
fpath = fn # それを書出ファイル名に
return fpath #ループが終わればその新ファイル名を返す
            ~/uunzip.py (後半)


def u_unzip(zip_name=None #ZIPファイル名
, dir=None #解凍先ディレクトリ
, selections=[] #解凍対象ファイルの指定リスト
, encoding='cp932' #ZIPファイル側文字コード
, encoding0 = 'utf-8' #OS(コンソール入力)側文字コード
, encodings=['cp932', 'utf-8', 'euc-jp', 'iso2022_jp', 'utf_8_sig'
, 'Shift_JIS'] #日本語向け駄目押し文字コード
, test_all=False #全コーデックを試す
, answers = ['y', 'n', 'A', 'N', 'r'] #replace時のunzip準拠の選択肢
, msg_replace=u'\rreplace \"%s\"? [y]es, [n]o, [A]ll, [N]one, [r]ename: '
#同確認プロンプト
, msg_zippath=u'\rfilepath:' #zipファイル表示ヘッダ
, msg_new_name=u'\rnew name[%s]: ' #ファイル名変更のプロンプト
, msg_mkdir=u'\rcreating: \"%s\"' #ディレクトリ作成表示ヘッダ
, msg_exit=u'\r%s was stoped.' #'N'時のメッセージ(独自)
, msg_skip=u'\r\"%s\" was skipped over.'#'n'の時のメッセージ(独自)
, msg_unzip=u'\rinflating: \"%s\"' #解凍時のファイル表示ヘッダ
, msg_exists=u'uunzip: cannot find or open'
#zipファイルが無いとき
, msg_readerr=u'Cannot read this file as zip.'
#zipとして読めないとき
, zinfo_items = [u'Length ', u'Date', u'Time', u'Name']
#リスト項目名
, zinfo_widths = [9, 10, 5, 4] #リスト項目幅
, zinfo_line = u'-' #罫線用文字
, zinfo_files = u'files' #ファイル数の数詞
, ext='zip' #補完拡張子
, help_opt=['--hh', '--help'] #ヘルプオプション
, help=False #ヘルプ表示
, help_txt=None #ヘルプ文書
, pub_vanames=[] #公開変数リスト
, variables={}): #可変変数の現在値辞書
u""" defined uunzip command all functions
「uunzip」の本体関数
 ここは、ほぼ処理プロセスのみを記述。オプション追加等の処理分岐の変更は
ここで修正することになる。
 表示するリテラルについては、基本的に全てこの関数の引数に集約したので、
比較的容易に多言語化や用途変更の要望にも答えることが出来るものと思う。
"""
from sys import argv #コマンドライン引数
from zipfile import ZipFile, BadZipfile #ZIP形式の圧縮ファイルの操作
from os.path import split as fsplit #ファイルパスの分離
from os.path import exists, join, splitext #パスの存否判定, 結合
from os import makedirs #ファイルパスの新規作成
zipname = None
#### ヘルプ表示 ####
if zip_name==None or help==True: #zipnameがないか、helpが真なら、
prn_help(pub_vanames=pub_vanames, variables=variables
, help_txt=None) # ヘルプ表示
return
## 対象ZIPファイル名の確定 ##
elif zip_name:
zipname = exist_filename(filename=zip_name, ext=ext, message=msg_exists)
if zipname==None: #対象ZIPファイルが無いなら
return # 関数を抜けuunzip終端に至る
## 「unzip -l」相等の書庫情報一覧を表示 ##
if zipname and dir==None: #ZIPが実在ファイルで解凍先指定が無いなら、
prn_ZipInfo(zip_name=zipname, encoding=encoding, encodings=encodings
, msg_zippath=msg_zippath, zinfo_items=zinfo_items
, zinfo_widths=zinfo_widths, zinfo_line=zinfo_line
, zinfo_files=zinfo_files) #「unzip -l」相等の書庫情報一覧を表示
## 書庫の解凍処理 ##
elif zipname and dir: #第2引数以上指定で第1引数が実在ファイルで
print msg_zippath, zipname # その引数を画面出力
# 第2引数:解凍先(解凍時は第2引数の解凍先指定は必須になった 2012-10-02)#
# ZipFileオブジェクト生成 #
try:
z = ZipFile(zipname, 'r') # 第1引数のZIPを読込モードで開き
except:
print msg_readerr
return
# ZIP内ファイル名リストの取得 #
names = z.namelist() # 指定ZIP内ファイル名一覧を取得

#### 以下では標準コンソール入力から引数を取込む ####
## 解凍対象ファイルの特定 ##
f_list=[] # 解凍対象ファイル名のリスト
if selections==[]: # 解凍対象ファイル指定を省略したら、
f_list=names[:] # ZIP内の全ファイルを対象ファイルに
else: # 解凍対象ファイル指定が1つ以上なら、
f_list = and_items(list1=selections, list0=names
, encoding0=encoding0, encoding=encoding
, encodings=encodings, test_all=test_all)
# 文字コードをunicodeに揃え、完全一致で
# 包含する対象ファイル名のリストを取得
## 解凍対象ファイルを上書き確認の上解凍 ##
ans = '' # 処理確認の頭文字:'A'になったら全て処理
for name in f_list: # その一覧から順にファイル名を取出し
unicode_name = ucode(name, encoding, encodings, test_all)
# それをunicode文字列に変換
p, f = fsplit(unicode_name) # ファイル名をパスとファイル名に分割
# 書出し先パス文字列の生成 #
path = join(dir, p) # 書込先パス文字列生成 2012-10-02
# 個別ファイルの解凍先フルパス名 #
filepath = join(path, f) # 個別ファイルの解凍先パス名を生成
# 書出し先ディレクトリの整備 #
if not exists(path): # そのディレクトリが不存在なら
print msg_mkdir % (path) # 「作成中: ディレクトリ」の表示と
makedirs(path) # その作成をし、解凍時エラーを回避
# 解凍先の既存ファイル上書き対策 #
if exists(filepath) and not(ans=='A'): # 解凍先に同名ファイルがあれば
# 処理方法の確認入力 #
msg = msg_replace % (filepath) # 処理方法の確認にファイル名を附記
ans = select(prompt=msg # それを表示し、選択肢の英字1文字の
, answers=answers) # 入力を取得
# 処理方法確認の頭1文字別の処理実行 #
if ans in ['y', 'A']: # はいor全部の選択なら、解凍処理
unzip(z, unicode_name, name, filepath, msg_unzip)
elif ans=='r': # r(改名保存)の処理選択なら、
# 3桁の数字を附加して新たなファイル名を生成 #
prompt = msg_new_name # 新たなファイル名入力を促す文字列
fpath = new_name(wname=filepath, prompt=prompt, i=1)
# を表示し、非重複名を取得する
# その存在しないファイル名に変えて圧縮解凍 #
unzip(z, unicode_name, name, fpath, msg_unzip)
elif ans=='N': # 「中止」なら
print msg_exit % (splitext( #実際に叩いたコマンド名を附加した終了表示
fsplit(argv[0])[1])[0].upper())
z.close() # ZipFileオブジェクトを閉じ
exit() # システム終了
elif ans=='n': # 「いいえ」なら
print msg_skip % (f)# 処理を飛ばした旨表示
else: # 解凍先に同名ファイル無なら、
unzip(z, unicode_name, name, filepath, msg_unzip)
# 解凍処理
z.close() # ZipFileオブジェクトを閉じる
## 引数等不適合時の利用方法案内 ##
else: #想定外の場合なので
prn_help(pub_vanames=pub_vanames, help_txt=None)
print u'想定外です。'
### 【汎用系関数】 ###
def select(prompt='answer? [Y]es [N]o: ' #プロンプト表示文字列
, answers=['Y', 'N'] #選択肢
, upper=False): #大文字で比較
u"""command prompt such as input command of basic programing language
【処理方法の確認入力用の汎用関数】
コンソールにプロンプトを出し、求める範囲の返答の英字1文字を返す関数
"""
from sys import stdin #コマンドラインからの標準入力
print prompt, #プロンプトを表示し、処理確認
ans = stdin.readline()[0] #処理方法確認の頭1文字取得し
if upper: #新設upper引数が真なら
ans = ans.upper() # 大文字変換し
while not ans in answers: #リストの選択肢以外なら、
print prompt, # プロンプトを表示し
ans = stdin.readline()[0] # 処理方法の確認を繰り返す
if upper: # 新設upper引数が真なら
ans = ans.upper() # 大文字変換し
return ans #求める範囲と一致した文字1つを返す

## UNICODE文字列の文字幅 ##
# 「【PythonでCGI】listを一覧表示(データ型変換と段落)」2010年05月10日よりコピー
# ( http://pythonlife.seesaa.net/article/149444369.html )
def unicode_width(s, width={'Na':1, 'W':2, 'F':2, 'H':1, 'A':2, 'N':1}):
"""east asian width of unicode text line
UNICODE文字列の文字幅を返す関数
既定は東アジア文字セット利用前提としている
Na: Narrow 1 半角英数
H : Halfwidth 1 半角カナ
W : Wide 2 全角文字
F : Fullwidth 2 全角英数
N : Neutral 1 アラビア文字
A : Ambiguous 2 ギリシア文字、キリル文字
詳細はウィキペディア(Wikipedia): 東アジアの文字幅
http://ja.wikipedia.org/wiki/%E6%9D%B1%E3%82%A2%E3%82%B8%E3%82%A2%E3%81%AE%E6%96%87%E5%AD%97%E5%B9%85
Python unicodedata.east_asian_width()
http://www.python.jp/doc/2.5/lib/module-unicodedata.html
別解としては、 【UTF8文字幅揃え】unicodedata.east_asian_width() で紹介した
http://pythonlife.seesaa.net/article/133360506.html?1273463358
hush_puppyさんの「RubyとPythonで全角文字を半角文字2文字として数える」
http://d.hatena.ne.jp/hush_puppy/20090226/1235661269
がある。 恐らく、そちらのほうが処理は早いだろうから、一般にはhush_puppyさん作成分を
お使いになると良いかと思う。当方のこの関数は、曖昧、中立の文字の扱いを状況次第で
切替えることが出来たらいいなとの発想と、見た目で仕組みが判り易い方式とした迄である。
※ 残念なことにCJK拡張Bの漢字を指定するとeast_asian_width()はTypeErrorを吐く。
確かにプラットフォーム側の対応も課題なので、それでどうなのって言う感じだが、
場合によっては例外処理で補正した方が良いのかもしれない。
"""
from unicodedata import east_asian_width
n = 0
for c in s: # 1文字ずつ、字幅辞書にwidthに
n = n + width[east_asian_width(c)] # east_asian_width()が返す文字幅種別を入れ
return n # 幅の累計値を返す

## unicodeの左寄せ、中央寄せ、右寄せ用の即席関数 ##
def unicode_ljust(s, w):
u"""unicode左寄せ"""
width = unicode_width(s)
return s+''.ljust(w - width)
def unicode_center(s, w):
u"""unicode中央寄せ"""
width = unicode_width(s)
return ''.ljust((w - width)/2) + s + ''.ljust(w - width - (w - width)/2)
def unicode_rjust(s, w):
u"""unicode右寄せ"""
width = unicode_width(s)
return ''.ljust(w - width) + s
def ucode(s, encoding=None, encodings=['cp932', 'utf-8', 'euc-jp', 'iso2022_jp'
, 'utf_8_sig', 'Shift_JIS'], test_all=False, debug=0):
u"""unicode func with multiple encodings
文字列のunicode化を試す関数
encoding : 最優先の文字コードを設定
encodings: 蓋然性の高い順にコードセットを設定(既定値は日本語用途向け)
※ 追加でPython標準定義の全コーデックも試し、最初に通過したものでunicode化
"""
import sys
from encodings.aliases import aliases #Python 標準のコーデック別名辞書
all_encodings = aliases.values() #Python標準定義の全コーデック名
if test_all: #「下手な鉄砲も数打ちゃ中る」でいいなら、
#駄目押しで、Python標準定義の全コーデック名から、非自然言語系を除去したものを準備
all_encodings = sorted(set(all_encodings), key=all_encodings.index)
# 重複除去後
for c in all_encodings: # 全encodingsを1つずつ、
if ((len(c)>6 and c[-6:]=='_codec') # '_codec'が付く非自然言語系か、
or (len(c)>7 and c[-7:]=='_escape') # '_escape'が付くPythonリテラル変換か、
or c in ['rot_13', 'idna', 'punycode' # 暗号化,RFC3490/3492国際化Domain名
, 'unicode_internal', 'undefined']):# 内部表現,全例外送出なら、不要に付
all_encodings.remove(c) # 全encodingsから除去
all_encodings = sorted(set(all_encodings), key=all_encodings.index)
# 重複排除
encodingset=[] #試す全encodingの入れ物準備
if encoding: #コード指定が有るなら、
encodingset.append(encoding) # コードリストの先頭に挿入
if encodings or not encodings==[]: #優先encodingリストかの指定があるなら、
encodingset.extend(encodings) # 試す全encodingに優先リストを追記
if not sys.stdin.encoding in encodingset: #標準入力のencodingがないなら、
encodings.append(sys.stdin.encoding) #標準入力のencodingを末尾に補完(馬鹿避け)
#encodingset内のencoding名をpythonの内部名称形式(小文字, '-'→'_')に揃える
i = 0 #listの添字
for e in encodingset: #試す全encodingから順に
try:
e_lower = e.lower().replace('-', '_') # pythonの内部名称の形式に揃え
encodingset[i] = aliases[e_lower] # その別名登録があったら、それに置換
except:
if e_lower in all_encodings: # pythonの内部名称と一致したら、
encodingset[i] = e_lower # それに置換
i += 1 # 次の添字へ進み、ループ継続
# test_allがTrueなら、試す全encodingに自然言語系Python標準定義のencoding追記
if test_all: #「下手な鉄砲も数打ちゃ中る」でいいなら、
encodingset.extend(all_encodings) # 試す全encodingに、この全encodingsを追加し
# 試す全encodingから重複排除
encodingset = sorted(set(encodingset), key=encodingset.index)
# 生成したリスト順のコーデックでunicode変換を試み成なら変換結果を、全て否ならそのままを返す #
for c in encodingset: #そのコードリストから1つずつコードを取出し
try: # そのコードで変換を試し
return unicode(s, c) # 成功したら、変換文字列を返す
except: # 例外発生なら、
pass # スルーし続ける
return s #結局全滅だったなら無責任に元文字列を返す

def replaces(s, alt_dic={u'\n':u'\\n', u'\t':u'\\t', u'\r':u'\\r'
, u'\a':u'\\a', u'\'':u'\\\'', u'\"':u'\\\"'}):
u"""replace to escape sequences
特殊文字をpython表記に置替える用途の関数
「辞書指定で複数置替え可能なreplaces()文字列置替関数」(2012-01-29)の
別用途のサブセット http://pythonlife.seesaa.net/article/249163772.html
"""
for key in alt_dic: #置替辞書の要素を1つずつ
s = s.replace(key, alt_dic[key]) # 文字列内でその値に置換し
return s #返す

def main(debug=0):
u"""send console command parameters to u-unzip() func.
コマンド引数を処理しu-unzip()関数の引数を確定する関数
"""
from sys import argv
from re import compile, match, search
## uunzip実行時の既定の引数 ##
zip_name = None #ZIPファイル変数準備
dir = None #解凍先ディレクトリ変数準備
encoding = 'cp932' #ZIPファイル側文字コード
encoding0 = 'utf-8' #OS(コンソール入力)側文字コード
encodings = ['cp932', 'utf-8', 'euc-jp', 'iso2022_jp', 'utf_8_sig'
, 'Shift_JIS'] #文字コード群(この順でunicode化を試行)
test_all = True #Python定義全codecを試す
selections = [] #解凍対象リスト変数
answers = ['y', 'n', 'A', 'N', 'r'] #replace時のunzip準拠の選択肢
msg_replace = u'\rreplace \"%%s\"? [%s]es, [%s]o, [%s]ll, [%s]one,\
[%s]ename: ' % tuple(answers) #上書確認プロンプト
msg_zippath = u'\rArchive: ' #zipファイル表示ヘッダ
zinfo_items = [u'Length ', u'Date', u'Time', u'Name']
#リスト項目名
zinfo_widths = [9 ,10 , 5 , 4] #リスト項目幅
zinfo_line = u'-' #罫線用文字
zinfo_files = u'files' #ファイル数の数詞
ext = 'zip' #ZIPファイルの補完拡張子
help_opt = ('--help', '--hh') #ヘルプオプション
help = False #ヘルプ表示
help_file = '/usr/local/etc/uunzip/man/uunzip.hlp' #外付ヘルプファイル
help_txt = read_help(help_file) #ヘルプ文書
lang = 'en' #表示言語

#「上書きしますか?」と処理確認(選択肢:「はい, いいえ, 全部, 中止, 改名」)
msg_new_name = u'\rnew name[%s]: ' #ファイル名変更のプロンプト
msg_exists = u'uunzip: cannot find or open' #zipファイルが無いとき
msg_exit = u'\r%s was stoped.' #終了時のメッセージ(独自)
msg_skip = u'\r\"%s\" was skipped over.' #上書きしない時のメッセージ(独自)
msg_mkdir = u'\rcreating: \"%s\"' #ディレクトリ作成表示ヘッダ
msg_unzip = u'\rinflating: \"%s\"' #解凍時のファイル表示ヘッダ
msg_readerr = u'Cannot read this file as zip.\nIs this a zip file?' \
#zipとして読めないとき
param = u'param' # 引数の表示略称
blockup_list = ['blockup_list', 'pub_vanames', 'variables', 'match', 'argv'
, 'compile', 'p_f', 'p_i', 'search', 'i', 'itm', 'val', 'va', 'value'
, 'zip_name', 'dir', 'selections', 'answers', 'debug']
#封鎖変数(コマンド引数非公開)
pub_vanames = locals()
pub_vanames = set(pub_vanames.keys()) - set(blockup_list)
pub_vanames = sorted(pub_vanames)
if len(argv)==1: #引数無しなら
#zip_name = None # zip_nameはNoneのまま、先へ
pass
elif len(argv)>1: #それ以外で引数が1つ以上あり、
if argv[1] in help_opt: # 第1引数がhelp_optリストの文字列なら
help=True # help表示を真とする
# 引数を検査し、u-unzip()関数に渡す引数を確定する
if len(argv)==2: # 第1引数のみなら、ZIPファイル名として
# 第1引数がZIPファイルなら、ZIP内書庫ファィル一覧表示へ
zip_name = argv[1] # 代入し、先へ
elif len(argv)>2: # 2つ以上の引数があるなら、
# 引数内容から、各種オプション、ZIPファイルそして解凍先を確定する。
#オプション引数は「変数名=変数値」の形のみで、unzipとは異なる
i = 0 # 非Option引数カウンタ
p_i = compile('^[+-]*[0-9]+$') # 整数文字列パターン
p_f = compile('^[+-]*[0-9\.]+$') # 浮動小数点文字列パターン
for itm in argv[1:]: # コマンド引数を順に1つずつ
val = unicode(itm, encoding0).split('=', 1)
# 最初の「=」による2分割list
if len(val)==1 and i==0: # 「=」分割不能だった1番目は、
zip_name = ucode(itm, encoding0) # ZIPファイル名の引数として代入
i += 1 # 非Option引数カウンタを進める
elif len(val)==1 and i==1: # でなく「=」分割不能だった2番目は、
dir = ucode(itm, encoding0) # 解凍先の引数として代入
i += 1 # 非Option引数カウンタを進める
elif len(val)==1 and i>1: # でなく「=」分割不能の以降の分は
selections.append(u'%s' % ( # unicode化して試てから
ucode(itm, encoding0))) # 解凍対象リストに追加
i += 1 # 非Option引数カウンタを進める
## これ以下が「変数名=変数値」の形のオプション引数の設定 ##
elif (len(val)==2 # でなく「=」で分割済で、且つ
and not val[0] in blockup_list>1): # 封鎖変数名にないなら、
va =val[0] # 最初の「=」の前のものを変数名に
value = val[1] # 最初の「=」の後のものを変数値に
#以下で変数vaに変数値valueを代入処理する
if ((value[0]=='[' and value[-1]==']') or (value[0]=='('
and value[-1]==')')): # 丸または、角括弧囲みなら、
exec '%s = %s' % (va, value) # listまたはtupleとして代入(※)
elif (value=='None' or value=='True' or value=='False'):
# 論理等のシステム定数なら
exec u'%s = %s' % (va, value) # それとして代入
elif match(p_f, value): # 浮動小数点パターン合致なら
exec u'%s = %s' % (va, value.strip())
# それとして代入
elif match(p_i, value): # 整数値パターン合致なら
exec u'%s = %d' % (va, int(value.strip()))
# それとして代入
else: # それ以外は
exec u'%s = u\'%s\'' % (va, value)
# ユニコード文字列として代入
if lang=='ja':## A.日本語表示 ##
msg_zippath = u'\r書庫ファイル: ' #zipファイル表示ヘッダ
msg_replace = u'\r既存ファイル:\"%%s\"\nこれを上書きしても宜しいのですか?\n\
やる[%s], 抜かす[%s], 有る分全部上書き[%s], 何もせず終了[%s], 別名なら保管[%s]:\
' % tuple(answers) # 上書きの処理確認プロンプト
msg_new_name = u'\r新たな名前[%s]: ' # ファイル名変更のプロンプト
msg_exit = u'\r%s は以降の処理を中止しました。' # 終了時のメッセージ(独自)
msg_skip = u'\r\"%s\" を飛ばしました。' # 上書きしない時のメッセージ(独自)
msg_mkdir = u'\r作成中: \"%s\"' # ディレクトリ作成表示ヘッダ
msg_unzip = u'\r解凍中: \"%s\"' # 解凍時のファイル表示ヘッダ
msg_exists = u'uunzip: 探せないか開けません' # zipファイルが無いとき
msg_readerr = u'ZIPとして読めません。\nこれがZIPファイルなら再取得をお勧めします。'
# zipとして読めないとき
zinfo_items = [u'サイズ ', u'年-月-日', u'時:分', u'ファイル名']
# リスト項目名
zinfo_files = u'件' # ファイル数の数詞
param = u'引数' # 引数
variables = locals() #変更可能な変数

if debug>0: #For debug only
lv = locals()
vals = lv.keys()
vals.sort()
for v in vals:
if not v in blockup_list:
if type(lv[v]) is type('a') or type(lv[v]) is type(u'a'):
print u'%-12s: u\'%s\'' % (v, replaces(ucode(lv[v])))
elif type(lv[v]) is type(['list']):
s = u'%-12s: [' % (v)
v_list = []
for it in lv[v]:
if type(it) is type('a') or type(it) is type(u'a'):
v_list.append(u'u\'%s\'' % (ucode(it)))
elif type(it) is type(1) or type(it) is type(1.2):
v_list.append(u'%f' % (it))
s += ', '.join(v_list)
s += u']'
print s
else:
print u'%-12s: ' % (v), lv[v]

## uunzipを実行 ##
u_unzip(zip_name=zip_name, dir=dir, selections=selections
, encoding=encoding, encoding0=encoding0, encodings=encodings
, test_all=test_all, answers=answers, msg_replace=msg_replace
, msg_zippath=msg_zippath, msg_new_name=msg_new_name
, msg_exit=msg_exit, msg_skip=msg_skip, msg_mkdir=msg_mkdir
, msg_unzip=msg_unzip, msg_exists=msg_exists
, msg_readerr=msg_readerr, zinfo_items=zinfo_items
, zinfo_widths=zinfo_widths, zinfo_line=zinfo_line
, zinfo_files=zinfo_files, help_opt=help_opt, help=help
, help_txt=help_txt, pub_vanames=pub_vanames, variables=variables)

if __name__ == "__main__":
main(debug=0)
posted by Mire at 03:35 | Comment(0) | TrackBack(0) | Pythonプログラミング | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/298750061
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック
月額見放題1,000円開始キャンペーンバナー(画像ありver)
紺碧の艦隊 ルパン三世 GREAT CHASE クリックプロモーション
<< 2013年01月 >>
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
カテゴリ
タグクラウド
ファン
利用中のオープンソース
最近のコメント
最近の記事
過去ログ
QRコード
レガシーなアプリはいかが?
Dell 法人のお客様ページ
  • 【法人様向け】デル、お得なキャンペーン情報
  • 法人のお客様向け ストレージソリューション
  • 法人のお客様向け ネットワークソリューション
  • 【SOHO法人様向け】デル・オンライン広告限定ページ
  • デル-個人のお客様ページ
  • 【個人のお客様向け】デル・オンライン広告限定ページ
  • オンライン広告限定キャンペーンページ
  • ソフトウェア&周辺機器 パソコン工房
    ツートップインターネットショップ(twotop.co.jp) マウスコンピューター/G-Tune
  • ×

    この広告は1年以上新しい記事の投稿がないブログに表示されております。