はてブロ@ama_ch

https://twitter.com/ama_ch

pbcopyで日本語もコピーできるようにする

Mac OS Xの固有コマンドに「pbcopy」というものがあります。
これは

% less hoge.txt | pbcopy

のようにすると、コマンドの実行結果を直接クリップボードに送ることができる優れもののコマンドです。
とても便利なんですが、日本語を含む*1結果をパイプするとコピーしてくれません。


いつも通りグーグル先生に聞いてみたところ、
UTF-8でpbcopyできるようにする - by edvakf in hatena
こちらに対処法が紹介されていました。

# pbcopyで日本語(UTF-8)がコピーできるようになる
#__CF_USER_TEXT_ENCODING=0x1F5:1:14    # 元の値
__CF_USER_TEXT_ENCODING=0x1F5:0x8000100:0x8000100
export __CF_USER_TEXT_ENCODING

これを.bashrcや.zshrcにに書いておけば良いみたいです。念のため、先に「echo $__CF_USER_TEXT_ENCODING」で元の値を確認しておくことをオススメします!

17:30追記

こっちの方が良さそう。

# pbcopyで日本語(UTF-8)がコピーできるようになる
#__CF_USER_TEXT_ENCODING=0x1F5:1:14    # 元の値
__CF_USER_TEXT_ENCODING=0x1F5:0x8000100:14
export __CF_USER_TEXT_ENCODING


__CF_USER_TEXT_ENCODINGの持つ3つの値は、
1個目:おそらくUID

ama-ch% echo $__CF_USER_TEXT_ENCODING                                                                [~]
0x1F5:0x8000100:14
ama-ch% id    # idの参照                                                                       
uid=501(ama-ch) gid=20(staff) groups=20(staff),98(_lpadmin),81(_appserveradm),101(com.apple.sharepoint.group.1),79(_appserverusr),80(admin)

ama-ch% printf "%#x\n" $UID    # UIDを16進数表記                                                        [~]
0x1f5

このように、UIDと一致します。


2個目:エンコーディング
0x08000100がUTF-8を表すらしい。
参考:Terminal.appで日本語をpbcopyできない件、fakeclipで解決したよ - kei-os2007 no life, no Vim - vimグループ
元々の1がここには載っていないのでよくわかりません。Shift-jisかな?


3個目:システム言語
3つめの値はシステム言語らしく、日本語だと14になるようです。
先程はこの値も0x08000100にしていましたが、これは14のままでもpbcopyは動くようなので14に戻しました。

*1:多分

Emacsでカーソル位置から行頭まで削除する方法

Emacsには、デフォルトでカーソル位置から行頭まで削除(キル)するキーバインドが設定されていません。
C-u 0 C-kとかM-0 C-kでできます*1が、個人的によく使う機能なので1ストロークでいきたいですね。
なんかやり方ないかなーと探していたら、こんな便利なものがあるじゃない!

;; define the function to kill the characters from the cursor
;; to the beginning of the current line
(defun backward-kill-line (arg)
"Kill chars backward until encountering the end of a line."
(interactive "p")
(kill-line 0))

EmacsWiki: Backward Kill Line

これを.emacs.elに貼り付けて、C-S-kにglobal-set-keyします。

;; カーソル位置から行頭まで削除する
(defun backward-kill-line (arg)
  "Kill chars backward until encountering the end of a line."
  (interactive "p")
  (kill-line 0))
;; C-S-kに設定
(global-set-key (kbd "C-S-k") 'backward-kill-line)

設定を保存したら、

M-x load-file
.emacs.el

で動くようになります。


Emacsがまた便利になりました!やったね!!!

追記

C-u 0 C-k
M-0 C-k

なぜこれで行頭からカーソル位置まで削除できるのかわからなかったので、C-kの引数の取り方について調べてみました。
Emacsでヘルプを参照

C-h k C-k

C-h kで、次に入力したコマンドの解説が表示されます。


一部抜粋:

With prefix argument, kill that many lines from point.
Negative arguments kill lines backward.
With zero argument, kills the text before point on the current line.

対訳:

先頭に引数を付けると、カーソル位置から複数行をキルできます。
負の引数は後ろの行をキルします。
引数0は、現在行のカーソル位置から後ろをキルします。

なるほど、C-kに与える引数で動作が変わるのか!

*1:なぜこれでできるのかは分からない。

zshをMacPortsでアップデートする

zshは、以下のコマンドでバージョン確認ができます。

% zsh --version
zsh 4.3.4 (powerpc-apple-darwin9.0)

現在のバージョン(最初からMacに入っていたもの)は4.3.4ですね。


MacPortszshを検索してみると・・・

% port search zsh                                                                              [~]
ctags @5.7 (devel)
    Reimplementation of ctags(1)

lesspipe @1.53 (textproc)
    lesspipe is an input filter for the pager less.

zsh @4.2.7 (shells)
    Zsh is a UNIX command interpreter (shell)

zsh-devel @4.3.9 (shells)
    Zsh is a UNIX command interpreter (shell)

Found 4 ports.

4.3.9というバージョンが見つかりました。今のバージョンより新しいので、アップデートしましょう。


MacPortszshをインストールします。

% sudo port install zsh-devel                                                                  [~]
Password:
--->  Fetching gdbm
--->  Attempting to fetch gdbm-1.8.3.tar.gz from ftp://ftp.dti.ad.jp/pub/GNU/gdbm
--->  Verifying checksum(s) for gdbm
--->  Extracting gdbm
--->  Applying patches to gdbm
--->  Configuring gdbm
--->  Building gdbm
--->  Staging gdbm into destroot
--->  Installing gdbm @1.8.3_1
--->  Activating gdbm @1.8.3_1
--->  Cleaning gdbm
--->  Fetching zsh-devel
--->  Attempting to fetch zsh-4.3.9.tar.bz2 from ftp://ftp.iij.ad.jp/pub/misc/zsh/
--->  Attempting to fetch zsh-4.3.9.tar.bz2 from http://internap.dl.sourceforge.net/zsh
--->  Verifying checksum(s) for zsh-devel
--->  Extracting zsh-devel
--->  Configuring zsh-devel
--->  Building zsh-devel
--->  Staging zsh-devel into destroot
--->  Installing zsh-devel @4.3.9_0
--->  Activating zsh-devel @4.3.9_0
--->  Cleaning zsh-devel

無事インストールできました。
MacPortsでインストールしたものは/opt/local以下に入るので、インストールしたzshの場所は/opt/local/bin/zshになります。


ちょっと実験。

% whereis zsh                                                                                  [~]
/bin/zsh
% /bin/zsh --version                                                                           [~]
zsh 4.3.4 (powerpc-apple-darwin9.0)
% zsh --version                                                                                [~]
zsh 4.3.9 (i386-apple-darwin9.6.0)
% /opt/local/bin/zsh --version                                                                 [~]
zsh 4.3.9 (i386-apple-darwin9.6.0)

あれ、zsh --versionと/bin/zsh --versionの挙動が違うのはなぜ?


よくわからないけど、とりあえずログインシェルをMacPortsでインストールした/opt/local/bin/zshに変更しておきます。

% chsh -s /opt/local/bin/zsh                                                                   [~]
Changing shell for ama-ch.
Password for ama-ch: 
chsh: /opt/local/bin/zsh: non-standard shell

あれ、エラーだ。ノンスタンダードシェルとか言われます。

"non-standard shell"でぐぐったら一発でした。Macportsでインストールしたzshにchshする方法 - Hello, world! - s21gにやり方が書かれていました。

% cat /etc/shells                                                                              [~]
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/opt/local/bin/zsh    # これを追加
% chsh -s /opt/local/bin/zsh                                                                   [~]
Changing shell for ama-ch.
Password for ama-ch: 

ターミナルを再起動し、

% finger ama-ch                                                                                [~]
Login: ama-ch                           Name: ama-ch
Directory: /Users/ama-ch                Shell: /opt/local/bin/zsh
On since 木  1  8 19:00 (JST) on console, idle 1 day 16:55 (messages off)
On since 土  1 10 11:45 (JST) on ttys000 (messages off)
On since 木  1  8 19:19 (JST) on ttys001, idle 2:45
No Mail.
No Plan.
% /opt/local/bin/zsh --version                                                                 [~]
zsh 4.3.9 (i386-apple-darwin9.6.0)

"Shell:"がログインシェルです。
Shell: /opt/local/bin/zshとなっているので大丈夫そうです!
あとは

% sudo port upgrade installed

と打てば、MacPortsがアップデートしてくれます。MacPortsべんり!

zsh入門してみたら便利すぎて鼻息が抑えられない

「シェル?ターミナルでコマンド叩くだけでしょ。デフォルトのbashで十分」
そう思っていた僕ですが、漢のzshを見て考えが180度変わりました。zshスゴイ。愛してる。
zshはどうにも情報が得にくくて敬遠していたけど*1、漢のzshは分かりやすくて素晴らしい!僕も漢としての第一歩を踏み出せそうな気がしてきました。
連載の5回まで読んでやってみたので、記録しておきます。

まずはbashにお別れ

最初はターミナルでzshを叩いて試してたけど、やればやるほどデフォルトで良いんじゃないか、いやむしろデフォルトでお願いします、という気持ちが強くなったので、ログインシェルを変更。さよならbash、今までありがとう。

$ chsh -s /bin/zsh

これで、次回以降は最初からzshが使えます。

ところでzshって何て読むの?

「ぜっとしぇる」で正しいはず!
Z Shell - Wikipedia

漢の道程

.zshrcを作り、bashの設定を引き継ぐ

zshは設定を.zshrcに書く。
ホームディレクトリに.zshrcファイルを作り、.bashrcや.bash_profileに書いていた設定を適宜コピー。丸ごとコピーでもいいのかな?
あとは、.zshrcにゴリゴリ設定を書いて興奮しまくればよし!

.zshrcの編集と読み込み

.zshrcを編集したら、

% source ~/.zshrc

で再度読み込むことができる。

補完機能
# 補完機能
autoload -U compinit
compinit

これで、補完機能が使える。Tabでコマンド名やオプションなど、色々補完できる!

プロンプト

【コラム】漢のzsh (2) 取りあえず、プロンプトを整えておく。カッコつけたいからねの例とほとんど同じ。

# プロンプトの設定
case ${UID} in
0)
    PROMPT="%{^[[31m%}%n%%%{^[[m%} "
    RPROMPT="[%~]"
    PROMPT2="%B%{^[[31m%}%_#%{^[[m%}%b "
    SPROMPT="%B%{^[[31m%}%r is correct? [n,y,a,e]:%{^[[m%}%b "
    [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
        PROMPT="%{^[[37m%}${HOST%%.*} ${PROMPT}"
    ;;
*)
    PROMPT="%{^[[31m%}%n%%%{^[[m%} "
    RPROMPT="[%~]"
    PROMPT2="%{^[[31m%}%_%%%{^[[m%} "
    SPROMPT="%{^[[31m%}%r is correct? [n,y,a,e]:%{^[[m%} "
    [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
        PROMPT="%{^[[37m%}${HOST%%.*} ${PROMPT}"
    ;;
esac

上記設定の"^["は文字列ではなくエスケープ記号なので、そのままコピペすると動かない。
Emacsなら、置換対象を"^["、置換文字を"C-q ESC"で変換すると動く。
プロンプトが「ユーザー名% 」になっていて、現在のパスを右側に表示するようにした。
パスを右側表示にすると、左プロンプトの長さが一定になってこれがなにげに快適!

コマンド履歴

指定したファイルに、実行したコマンドの履歴が記録される。重複するものは記録しないし、一度入力したコマンドは後述の履歴検索からすべて辿れるようになる。すごいぞzsh

# コマンド履歴
HISTFILE=~/.zsh_history
HISTSIZE=6000000
SAVEHIST=6000000
setopt hist_ignore_dups     # ignore duplication command history list
setopt share_history        # share command history data
コマンド履歴検索

以下の設定で、コマンドの履歴を検索できる。

# コマンド履歴検索
autoload history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^P" history-beginning-search-backward-end
bindkey "^N" history-beginning-search-forward-end

Ctrl-P/Ctrl-Nで、入力中の文字から始まるコマンドの履歴が表示される。"l"と入力した状態でCtrl-Pを押すと、"ls"や"less"が次々に表示されていく。
bashだと"!hoge"でhogeから始まる最後のコマンドを実行できるけど、使い勝手が悪かった。zshのこの設定の方が無理がなくて素敵ですね!

その他いろいろ
# ディレクトリ名を入力するだけで移動
setopt auto_cd

"cd"を入力しなくても移動できるようになる!
"~"とか".."とだけ打てば動けるのは、ありがたい。

# 移動したディレクトリを記録しておく。"cd -[Tab]"で移動履歴を一覧
setopt auto_pushd

"cd -[Tab]"で、移動履歴が表示されるようになる。
ひとつ前にいたディレクトリに戻りたいけど、パスが長くて面倒・・・という時に効果絶大!

# コマンド訂正
setopt correct

コマンドを打ち間違えた時に、近いコマンドを提案してくれる。何この便利機能、賢すぎる!

# 補完候補を詰めて表示する
setopt list_packed 

Tabで補完候補を表示する際、画面に収まらない場合は表示間隔を詰めてなるべく収まるようにしてくれる。細かいところで気が利いてるなぁ〜。

# 補完候補表示時などにピッピとビープ音をならないように設定
setopt nolistbeep

ビープ鳴りまくると結構ストレスなので、設定しておきます。

# Emacsライクキーバインド設定
bindkey -e 

最初からEmacsキーバインドだと思うんだけどな?いちおう、これも設定。
vim使いにはvimキーバインド設定もありますよ!

zshはよいものだ

まだ全然理解できていませんが、とても使いやすいということは分かりました。
色々と調べて、もっと使いこなせるようになりたいです!

*1:そもそもシェルをいじったり変えようとしたことがなかった

iconvコマンドで使えるエンコード名

メモメモ。

$ iconv -l
ANSI_X3.4-1968 ANSI_X3.4-1986 ASCII CP367 IBM367 ISO-IR-6 ISO646-US ISO_646.IRV:1991 US US-ASCII CSASCII
UTF-8 UTF8
UTF-8-MAC UTF8-MAC
ISO-10646-UCS-2 UCS-2 CSUNICODE
UCS-2BE UNICODE-1-1 UNICODEBIG CSUNICODE11
UCS-2LE UNICODELITTLE
ISO-10646-UCS-4 UCS-4 CSUCS4
UCS-4BE
UCS-4LE
UTF-16
UTF-16BE
UTF-16LE
UTF-32
UTF-32BE
UTF-32LE
UNICODE-1-1-UTF-7 UTF-7 CSUNICODE11UTF7
UCS-2-INTERNAL
UCS-2-SWAPPED
UCS-4-INTERNAL
UCS-4-SWAPPED
C99
JAVA
CP819 IBM819 ISO-8859-1 ISO-IR-100 ISO8859-1 ISO_8859-1 ISO_8859-1:1987 L1 LATIN1 CSISOLATIN1
ISO-8859-2 ISO-IR-101 ISO8859-2 ISO_8859-2 ISO_8859-2:1987 L2 LATIN2 CSISOLATIN2
ISO-8859-3 ISO-IR-109 ISO8859-3 ISO_8859-3 ISO_8859-3:1988 L3 LATIN3 CSISOLATIN3
ISO-8859-4 ISO-IR-110 ISO8859-4 ISO_8859-4 ISO_8859-4:1988 L4 LATIN4 CSISOLATIN4
CYRILLIC ISO-8859-5 ISO-IR-144 ISO8859-5 ISO_8859-5 ISO_8859-5:1988 CSISOLATINCYRILLIC
ARABIC ASMO-708 ECMA-114 ISO-8859-6 ISO-IR-127 ISO8859-6 ISO_8859-6 ISO_8859-6:1987 CSISOLATINARABIC
ECMA-118 ELOT_928 GREEK GREEK8 ISO-8859-7 ISO-IR-126 ISO8859-7 ISO_8859-7 ISO_8859-7:1987 ISO_8859-7:2003 CSISOLATINGREEK
HEBREW ISO-8859-8 ISO-IR-138 ISO8859-8 ISO_8859-8 ISO_8859-8:1988 CSISOLATINHEBREW
ISO-8859-9 ISO-IR-148 ISO8859-9 ISO_8859-9 ISO_8859-9:1989 L5 LATIN5 CSISOLATIN5
ISO-8859-10 ISO-IR-157 ISO8859-10 ISO_8859-10 ISO_8859-10:1992 L6 LATIN6 CSISOLATIN6
ISO-8859-11 ISO8859-11 ISO_8859-11
ISO-8859-13 ISO-IR-179 ISO8859-13 ISO_8859-13 L7 LATIN7
ISO-8859-14 ISO-CELTIC ISO-IR-199 ISO8859-14 ISO_8859-14 ISO_8859-14:1998 L8 LATIN8
ISO-8859-15 ISO-IR-203 ISO8859-15 ISO_8859-15 ISO_8859-15:1998 LATIN-9
ISO-8859-16 ISO-IR-226 ISO8859-16 ISO_8859-16 ISO_8859-16:2001 L10 LATIN10
KOI8-R CSKOI8R
KOI8-U
KOI8-RU
CP1250 MS-EE WINDOWS-1250
CP1251 MS-CYRL WINDOWS-1251
CP1252 MS-ANSI WINDOWS-1252
CP1253 MS-GREEK WINDOWS-1253
CP1254 MS-TURK WINDOWS-1254
CP1255 MS-HEBR WINDOWS-1255
CP1256 MS-ARAB WINDOWS-1256
CP1257 WINBALTRIM WINDOWS-1257
CP1258 WINDOWS-1258
850 CP850 IBM850 CSPC850MULTILINGUAL
862 CP862 IBM862 CSPC862LATINHEBREW
866 CP866 IBM866 CSIBM866
MAC MACINTOSH MACROMAN CSMACINTOSH
MACCENTRALEUROPE
MACICELAND
MACCROATIAN
MACROMANIA
MACCYRILLIC
MACUKRAINE
MACGREEK
MACTURKISH
MACHEBREW
MACARABIC
MACTHAI
HP-ROMAN8 R8 ROMAN8 CSHPROMAN8
NEXTSTEP
ARMSCII-8
GEORGIAN-ACADEMY
GEORGIAN-PS
KOI8-T
CP154 CYRILLIC-ASIAN PT154 PTCP154 CSPTCP154
KZ-1048 RK1048 STRK1048-2002 CSKZ1048
MULELAO-1
CP1133 IBM-CP1133
ISO-IR-166 TIS-620 TIS620 TIS620-0 TIS620.2529-1 TIS620.2533-0 TIS620.2533-1
CP874 WINDOWS-874
VISCII VISCII1.1-1 CSVISCII
TCVN TCVN-5712 TCVN5712-1 TCVN5712-1:1993
ISO-IR-14 ISO646-JP JIS_C6220-1969-RO JP CSISO14JISC6220RO
JISX0201-1976 JIS_X0201 X0201 CSHALFWIDTHKATAKANA
ISO-IR-87 JIS0208 JIS_C6226-1983 JIS_X0208 JIS_X0208-1983 JIS_X0208-1990 X0208 CSISO87JISX0208
ISO-IR-159 JIS_X0212 JIS_X0212-1990 JIS_X0212.1990-0 X0212 CSISO159JISX02121990
CN GB_1988-80 ISO-IR-57 ISO646-CN CSISO57GB1988
CHINESE GB_2312-80 ISO-IR-58 CSISO58GB231280
CN-GB-ISOIR165 ISO-IR-165
ISO-IR-149 KOREAN KSC_5601 KS_C_5601-1987 KS_C_5601-1989 CSKSC56011987
EUC-JP EUCJP EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE CSEUCPKDFMTJAPANESE
MS_KANJI SHIFT-JIS SHIFT_JIS SJIS CSSHIFTJIS
CP932
ISO-2022-JP CSISO2022JP
ISO-2022-JP-1
ISO-2022-JP-2 CSISO2022JP2
CN-GB EUC-CN EUCCN GB2312 CSGB2312
GBK
CP936 MS936 WINDOWS-936
GB18030
ISO-2022-CN CSISO2022CN
ISO-2022-CN-EXT
HZ HZ-GB-2312
EUC-TW EUCTW CSEUCTW
BIG-5 BIG-FIVE BIG5 BIGFIVE CN-BIG5 CSBIG5
CP950
BIG5-HKSCS:1999
BIG5-HKSCS:2001
BIG5-HKSCS BIG5-HKSCS:2004 BIG5HKSCS
EUC-KR EUCKR CSEUCKR
CP949 UHC
CP1361 JOHAB
ISO-2022-KR CSISO2022KR
CP856
CP922
CP943
CP1046
CP1124
CP1129
CP1161 IBM-1161 IBM1161 CSIBM1161
CP1162 IBM-1162 IBM1162 CSIBM1162
CP1163 IBM-1163 IBM1163 CSIBM1163
DEC-KANJI
DEC-HANYU
437 CP437 IBM437 CSPC8CODEPAGE437
CP737
CP775 IBM775 CSPC775BALTIC
852 CP852 IBM852 CSPCP852
CP853
855 CP855 IBM855 CSIBM855
857 CP857 IBM857 CSIBM857
CP858
860 CP860 IBM860 CSIBM860
861 CP-IS CP861 IBM861 CSIBM861
863 CP863 IBM863 CSIBM863
CP864 IBM864 CSIBM864
865 CP865 IBM865 CSIBM865
869 CP-GR CP869 IBM869 CSIBM869
CP1125
EUC-JISX0213
SHIFT_JISX0213
ISO-2022-JP-3
BIG5-2003
ISO-IR-230 TDS565
ATARI ATARIST
RISCOS-LATIN1


jumanがeuc-jpにしか対応してなくて困ったぞ
Terminal.appのエンコーディング設定をEUCにしたら一応動くけど、挙動がおかしくなるしscreenも動かなくなる・・・

  • 解析文をテキストに保存
  • iconv -f utf8 -t eucjp hoge.txt > hoge1.txt とかでeuc-jpに変換
  • Terminal.appの設定を日本語(EUC)にする
  • juman -B -e2 < hoge1.txt

こうしたら動くけどめんどくさい!シェルスクリプト書いても大して楽にならないしなぁ><
「juman utf8」とかでぐぐってもそれらしい情報がない。jumanはutf8で使えないのかー

pyspa challenge 第1回やってみた

トラバ送っていきなり答えのリンク張ってしまうのはどうかな?
と思ったので、リンクは張らないでおきます><
と思っていたけど、解答編からトラバがきたのでリンク張ります!

問題

pyspa challenge 第1回 - 西尾泰和のはてなダイアリー
http://d.hatena.ne.jp/nishiohirokazu/20081129/1227952375

*****の部分に適当なコードを入れてpyspaと表示されるようにせよ

第1問
print "".join(chr(ord(x) + 1) for x in *****)

chr(ord(x) + 1)が"pyspa"になるxを探します!
アルファベット1文字戻ればいいから、o,x,r,o,・・・"a"の前ってなんだっけ?


調べてみよう。

>>> ord("a")
97
>>> chr(96)
'`'

なるほど、"`"か!


というわけで、答えは

>>> print "".join(chr(ord(x) + 1) for x in "oxro`")
pyspa
第2問
import os
print "".join(os.__doc__[x] for x in[os.__doc__.*****(x) for x in "pyspa"])

os.__doc__ってなんだっけ・・・見てみよう。

>>> type(os.__doc__)
<type 'str'>
>>> print os.__doc__
OS routines for Mac, NT, or Posix depending on what system we're on.

This exports:
  - all functions from posix, nt, os2, mac, or ce, e.g. unlink, stat, etc.
  - os.path is one of the modules posixpath, ntpath, or macpath
  - os.name is 'posix', 'nt', 'os2', 'mac', 'ce' or 'riscos'
  - os.curdir is a string representing the current directory ('.' or ':')
  - os.pardir is a string representing the parent directory ('..' or '::')
  - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\')
  - os.extsep is the extension separator ('.' or '/')
  - os.altsep is the alternate pathname separator (None or '/')
  - os.pathsep is the component separator used in $PATH etc
  - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
  - os.defpath is the default search path for executables
  - os.devnull is the file path of the null device ('/dev/null', etc.)

Programs that import and use 'os' stand a better chance of being
portable between different platforms.  Of course, they must then
only use functions that are defined by all platforms (e.g., unlink
and opendir), and leave all pathname manipulation to os.path
(e.g., split and join).

ふむふむ、os.__doc__は文字列で、osモジュールの解説が入ってるのか。
文字列だと分かれば簡単だ!


問題のおさらい。

import os
print "".join(os.__doc__[x] for x in[os.__doc__.*****(x) for x in "pyspa"])

文字列os.__doc__の中から、"pyspa"の各文字のインデックスを取り出して連結する感じかな?


ん、インデックスを取り出す?

>>> import os
>>> "".join(os.__doc__[x] for x in[os.__doc__.index(x) for x in "pyspa"])
'pyspa'

できたー!

第3問
import os
os.system("python -m ***** | python -c 'import sys;(lambda x=sys.stdin.read():[sys.stdout.write(x[i]) for i in [67, 12, 31, 67, 36]])()'")

うおー全然わからない!!


先に言っておきますが、ものすごく無理矢理解きました...orz
とりあえず、ひとつずつ解読します。


-mという起動オプションは、

-m module module を sys.path 中から探し、スクリプトとして実行する

Python 2.4 クイックリファレンス

-cという起動オプションは、

-c command 与えられたコマンドを実行する (以降のセクションを参照)。 このオプションの後には、別のオプションを記述できない (コマンド自体の引数として扱われる)

Python 2.4 クイックリファレンス

なるほどなるほど。


問題のlambda式のところを抜き出してみます。

lambda x=sys.stdin.read():[sys.stdout.write(x[i]) for i in [67, 12, 31, 67, 36]])()

sys.stdin.read()で受け取った内容の、インデックス67,12,31,67,36*1を書き出すんだな。
受け取る内容が、

python -m ****

というわけか!
コマンド"python -m hoge"の出力が、インデックス67が"p",12が"y"となるhogeを探せば答えになりそうです。
-mオプションなんて使ったことないから、どうやって探せばいいんだろう><


・・・よし、総当たりで探そう!

#!usr/bin/env python
# -*- coding: utf-8 -*-
""" test.py
テストスクリプト
"""
import commands
import os
import sys

modulepath = "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5"
modules = commands.getoutput("ls *.py %s" % modulepath).split("\n")
modules = modules[modules.index(modulepath+":")+1:]

# 拡張子を取り除く
modulenames = []
for i in modules:
    try:
        modulenames.append(i[:i.index(".")])
    except:
        None
modulenames = set(modulenames)    # ダブりをまとめる

# 動かなくなるモジュール名
excepts = ["code", "pprint", "base64", "smtplib", "imaplib", "shlex", "quopri", "SimpleHTTPServer", "BaseHTTPServer", "UserString", "formatter", "uu", "pstats", "dis", "fileinput", "tokenize", "SimpleXMLRPCServer"]
# 動かないやつを削除
for i in excepts:
    modulenames.remove(i)

# 答え探し
for i,j in enumerate(modulenames):
    print "%d/%d executing" % (i,len(modulenames)) , j
    os.system('echo "%s" | pbcopy' % j)    # Mac用。オプションに与えるモジュール名をクリップボードへコピー(除外リストにすぐ加えられるように)
    output = commands.getoutput("python -m %s" % j)
    try:
        if output[67] == "p" and output[12] == "y":
            print j, "found!!!!!"
            break
    except:
        None

このスクリプトを実行すると、

$ python test.py
0/176 executing filecmp
1/176 executing heapq
2/176 executing LICENSE
・・・ 中略 ・・・
117/176 executing keyword
118/176 executing this
this found!!!!!

こんな感じで見つけてきます。
答えを見つけるまでは、たびたび入力待ち?みたいになって動かなくなるので、そういうのは適宜exceptsリストの中に放り込んでいきます。このへんを自動でできないのが僕の限界><


thisというモジュールが見つかったので、これを入れて実行してみます。

>>> os.system("python -m this | python -c 'import sys;(lambda x=sys.stdin.read():[sys.stdout.write(x[i]) for i in [67, 12, 31, 67, 36]])()'")
pyspa0

おぉ??
できたっぽいけど0ってなんだろう??


あ、

対話的環境でやっているときはos.systemが0を返すのでpyspa0って表示されちゃう。

だそうです。これで合ってるみたいですね。

12/3追記:答え

pyspa challenge1 解答編 - 西尾泰和のはてなダイアリー
thisってイースターエッグだったんだ、またひとつ勉強になりました!


pyspa challenge01 に挑戦してみた - 牌語備忘録
おぉ、問2間違ってた\(^o^)/ 4つってそういう意味だったのか・・・4つある同じ問題の1番短いのが問2の問題なのかと思(ry

*1:p,y,s,p,a

MacにFiremacsをインストールした

EmacsキーバインドFirefoxを操作できるアドオンFiremacsをインストールしました。


以下設定の個人的なメモ。

Option

「use Meta as "M-"」にチェックを入れると、Cmdキーで"M-"が入力できるようになる。Carbon Emacsと同じになるので便利!

View

j/hのスクロールはGmailGoogleリーダーのスレッド移動とかぶるので削除。
h/lでタブ移動できるのは便利だけど、当たり前ながらフォームにキャレットがあると文字が入力されるだけで移動できない。

Edit

KeyRemap4MacBookEmacs modeを使っていると、C-yがM-vにフックされているので、C-yをM-vに置き換える。
矢印キーのup,down,left,rightはわざわざ設定しなくても動くから削除。
C-SPCでのマークセットをしようとすると、コンテキストメニューが出る。なぜ? → 代わりにC-iを使う。
C-xuでのundoは面倒なのでC-/に変更。

Common

KeyRemap4MacBookでC-yがM-vにフックされているので、M-vのPage upを削除。
close tabがC-xkだと両手が必要だから、C-xC-cに。これなら片手で閉じられる。

その他

Firefoxがかなり便利になった。今までのキーバインドとがらりと変わったから少し混乱するけど・・・
フォーム内のテキスト編集もEmacs風にできるから、ダイアリーも書きやすい!
XKeymacsみたいにMac全体でEmacsキーバインドができればいいんだけどなぁ。