読者です 読者をやめる 読者になる 読者になる

AudacityとSoundflowerをセットするまで

昨年11月に長期プロジェクトがひと段落して、軽いマシンがほしかったので(重量的な意味で)、MacBookを購入した。

以前のマシンから環境をそのまま引き継ぐか、少し迷ったが、把握していない不要データごと引っ越すのもいやだな、と思ってイチからいろいろ入れていくことにした。

心配していたのはMicrosoft Office系、それからAdobe系の移行だったが、いずれも気が抜けるほどすんなりライセンスが通った。

それでほぼ環境は整ったと思っていたが、その長期プロジェクトの切り替えにともない、若干ながら&一時的ながら、自分の時間が増えたので、以前にやや中途半端なまま止まってしまった、音声入力を使った文字起こしのトライを再開しはじめたところ、
note103.hateblo.jp

音声ファイルをエディットするために使うAudacityと、Googleドキュメントの音声入力ツールに音を読み込ませるためのSoundflowerが入っていないことに気づいた。

で、これらは今までの経験上、何気に導入コストが高いというか、面倒という印象があったので(とくにSoundflower)、びくびくしながらコトを進めたが、存外これもすんなり完了し、しかしそれでも後から思い出すのはやはり面倒そうだなと思ったので、ここにメモしておくことにした。

contents:

Audacity

まずAudacityの導入から。
公式サイトは以下。

Audacity®

そのトップページからソフトをダウンロードして、

f:id:note103:20170101132854p:plain

それをダブルクリックしたら、あとは案内に従ってインストールすればOK。

え、それだけ? という感じだけど、そう、普通に使うだけならそれで充分。

なのだけど、面倒なのはエディット後のファイルをmp3に書き出すときで、wavやaiffならそのまま書き出せるけど(たしか)、mp3に書き出そうとすると、Lameというのが足りないよ、と言われる。

具体的には、以下のリンクを示されて、とりあえずちょっとこれ見とけ、みたいなアラートが出る。

http://manual.audacityteam.org/man/faq_installation_and_plug_ins.html#lame

なので、そのリンク先にあるMacの項目の、最初にあるリンクをクリックして、

f:id:note103:20170101132803p:plain

http://lame.buanzo.org/#lameosxdl

飛んだ先で一番それっぽい、「For Audacity 1.3.3 or later on Mac OS X 10.4 and greater (Intel or PPC),and Audacity 1.2.5 on OS X 10.4 and later (Intel)」というところからdmgファイルをダウンロード&インストール。

f:id:note103:20170101132835p:plain

これでmp3に書き出せるようになる。

しかし以前はもっと大変だった気がするんだけどなあ〜……だいぶラクになっているような。

なお、Audacityについては以下の記事でも少し触れている。

note103.hateblo.jp

Soundflower

次、Soundflower。

Soundflowerについても、以前に書いた以下の記事でちらちら紹介している。

とくに後者、というか冒頭でも示した文字起こしの記事は比較的最近なので、基本的にはそのくり返しになるのだけど、以下のGitHub上のリリースページから、

Releases · mattingalls/Soundflower · GitHub

現時点の最新版(2.02b)をダウンロード&インストールした。

Soundflowerの場合はとくにOSのバージョンや導入時期などによって、ソフトはもちろん、配布場所や開発者も違ったりする印象があるので、この機会にきちんとメモしておきたかった。

そういえば、つい最近どこかで見たブログ記事でも、「元のソフトは新しいOSでは動かないから」といって上記のfork版を紹介していたなあ、と思ったらはてなの開発者ブログだった。
developer.hatenastaff.com

なお、上の文字起こし記事でも触れているように、マシン内で音声ファイルを再生&録音させる際には、サウンド設定を入出力ともに「Soundflower(2h)」にする必要があるので、注意。

マシンの環境設定>サウンドからでも設定できるが、Optionを押しながらメニューバーのスピーカーマークを押せば簡単に選択できる。

さらに、それを再びマシンから普通に鳴らしたい場合には同様の方法で「出力」の方を「内蔵スピーカー」などに戻す必要があるので、再注意。

と思いつつ、今回このメモをまとめるために念のためあちこち検索してみたところ、以下のまとめがわかりやすく*1
rnkv.hatenadiary.jp

その中で紹介されていた「LadioCast」というツールがその辺をより便利にしてくれそうだった。

http://blog.kawauso.com/ladiocast

上に書いた設定でSoundflowerで録音すると、その間はマシン内で流している音を聴けないのだけど、これを使うと自分でもモニターを聴けるみたい。
今度録音するときから試してみたい。

また、そのLadioCastを使って録音する手順などについて、以下のQiitaの記事がスクリーンショット付きかつコンパクトな説明でわかりやすそうだった。(まだ精読していないけど)

qiita.com

そして作業へ

ということで、準備系のそれらについては以上。

本来の目的である文字起こしなどについては、また別の記事にまとめたい。

なお、当然のことながら上記の情報は本日(2017-01-01)時点のものにすぎないので、時間が経過すればするほどあくまで参考までに、という感じでお考えください。

*1:なんと昨日の更新だったみたい。シンクロニシティ……。

Vimで今見ているバッファを「現在日時+好きなファイル名」で保存する


結論

.vimrcに以下を入れて、

function! s:newfile(title)
  execute ":f /path/to/".strftime('%Y-%m-%d-%H-%M-%S').a:title.".txt"
endfunction
nnoremap <Leader>nf :<C-u>call <SID>newfile("_")<Left><Left>

マッピングに設定したコマンド(上の例ではLeaderキー*1を叩いてからnf)を打つと、コマンドラインに入力欄が出るので、そこに好きな語句を記入してエンターすると「現在日時_記入した語句」がファイル名になって保存される。

実演

f:id:note103:20161230104425g:plain

注)ここでは関数定義部分の「/path/to/」を「~/Dropbox/sample/」にしている。

経緯

半年ほど前に書いた以下の記事で、

note103.hateblo.jp

今見ているバッファを現在時刻のファイル名で保存する

というTIPを紹介したのだけど、そのときの方法は以下だった。

:w 版

function! s:wsave()
  execute ":w /path/to/".strftime('%Y-%m-%d-%H-%M-%S').".txt"
endfunction
nnoremap <silent> <Leader><Leader>w :<C-u>call <SID>wsave()<CR>

:f 版

function! s:fsave()
  execute ":f /path/to/".strftime('%Y-%m-%d-%H-%M-%S').".txt"
endfunction
nnoremap <silent> <Leader><Leader>f :<C-u>call <SID>fsave()<CR>

前者はコマンドラインモードにおける「:w」、つまり今見ているバッファはそのまま残しつつ、現在日時を刻印したファイル名で別名保存するもの。
後者は「:f」の形式、つまり今見ているバッファがそのファイル名になる、というもの。

これらの良いところは、ファイル名をわざわざ考えなくても、すぐに一意の(他と重複しない)ファイル名を付けて保存できること。
秒単位で刻印するので、カブることはほとんどない。

デメリットとしては、そのファイルを後から探そうというときに、日時だけのファイル名からでは内容を推測できないので、けっこう面倒なことになる。

よってこれらを使うのは、基本的に「後から見返すことはほとんどないと思うけど、念のため保存しておく」というときだけで、後で読み返す可能性が高いファイルに関しては、その内容を示すキーワードをファイル名に付加できるようにしたいと思っていた。

ただ、そうは思うものの僕の知識ではなかなか良い方法を思いつくことができなくて、しばらくは以下のようなマッピングでしのいでいた。

nnoremap <Leader><Leader>ww :w /path/to/.txt<Left><Left><Left><Left>
nnoremap <Leader><Leader>ff :f /path/to/.txt<Left><Left><Left><Left>
cnoremap <expr> ,df strftime('%Y-%m-%d-%H-%M')

この場合、Leaderを2回叩いてからffを叩くと、コマンドラインに「:f 保存したいディレクトリのフルパス/.txt」という文字列が出てきて、すでに「.txt」の一つ前の位置にカーソルが合っているので、そこに好きなファイル名を入れてすぐに保存できるようになっている。

前回のTIPS記事で示した「簡便に日時を出すマッピング」をコマンドラインモードでも使えるようにしているので(コードの3行目)、まず「,df」と打って日時を入れてから、何らかのキーワードを記入するという流れ。

実演

f:id:note103:20161229193602g:plain

これはこれで必要十分というか、まあ、これでもいいか……という感じになるのだけど、やはり理想は「手で記入するのはキーワードだけ」という状態であって、たとえ「,df」の3文字だけであっても、わざわざ現在日時を自分では打ちたくないというか、そこは人間が打たなくても最初から入っておいてほしい、という気持ちが強かった。

それであらためて粘って見つけたというか、考えたのが冒頭に示した現在の方法。
コード自体はガチャガチャしてちょっと恥ずかしいが、それでもこれなら現在日時は最初から入っていて、カーソルもすでに入力位置にあるので、ほんとに「キーワードだけ打ってエンターすれば確定」という感じになっている。

なお、「ファイル名とかわざわざ考えたくない。ただ一意のファイル名で即保存しておきたいだけ」という場合には、アンダーバーだけ消して(あるいはそれもそのままで)エンターすればこれでも希望は叶うが、それすら面倒という場合には(時々ある)、素直に前回紹介したマッピングを使っている。

ついでに言うと、この一連の方法では格納先のディレクトリがつねに一定なので、後から探すときにもけっこうラクというか便利。

余談

ちなみに以前は、このようなファイル保存&取り出しの用途では、@mattnさんオススメのmemolist.vimを使っていたのだけど、

mattn.kaoriya.net

今はこの手作り感満載な方法のほうが身の丈に合っているように思われ、これだけになっている。

さらにちなみに、memolistで実現できたはずの(使ってはいなかったが)grep機能というか、保存したファイル群からパターンを横断検索する機能としては、agというのを別途で使っていて、これも重宝している。

残る課題

ということで、とりあえず理想形に至ったかのように見える本件ですが、まだこれでも不満はあって、コマンドライン

:call <SNR>14_newfile("_")

なんて文字列が出てくるのはあまり美しくないというか、せめて

newfile("_")

で待機してくれるとか、あるいは対話型っぽく

Input a new filename >>

なんてふうに入力待ち状態になってほしい〜……とも思うので、その辺はもう少し模索を続けるかもしれない。

こういう小さな改善というか、便利さの追求というか、ストレス解消(発散ではなく解消)のための道行きというのは、本人がそれを意識的に望まなければなかなか進まないものなので、今後も自分の中の微弱な不満の声に敏感になって、拾い上げていきたいと思っている。

*1:デフォルトだとたしかバックスラッシュ。

プログラミング入門を支える技術

  • こちらはPerl入学式アドベントカレンダーの21日目の記事です。
  • 昨日は@karkador73さんの「Perl入学式に参加して、いろいろ刺激を受けた件」でした。
    • ぼくは普段 in東京のメンバーとしかつながりがないので、すごく新鮮な話でした。
    • @karkador73さんがPerl入学式に参加したきっかけは@sago35tkさんからの誘いということですが、その@sago35tkさんも比較的最近からの参加なので、そうやって新しいメンバーがどんどん新たなつながりを作っていく、というのはPerl入学式の稀有な特長だと思います。

  • さて、本日の記事では、ぼくが普段プログラミングに触れながら考えていることのうち、あまり他では聞かないというか、むしろ通常言われるセオリーみたいなものとは逆な気もするけど、人によっては役立つかもしれない視点というか、方針について、いくつか書いてみたいと思います。
  • 先に簡単に自己紹介をしておくと、ぼくは普段はフリーの編集者として過ごしていて、今はおもに坂本龍一さんの音楽全集「schola(スコラ)」の制作に携わっています。
    • じつはたまたま本日12/21(水)、1年ぶりとなるシリーズ最新刊が発売されました!!
    • いやー、偶然だなあ。(ハハ)
    • 公式ページのどこかにぼくの名前もあります。(→公式ページ

commmons: schola vol.16 Ryuichi Sakamoto Selections: Japanese Pop Music

commmons: schola vol.16 Ryuichi Sakamoto Selections: Japanese Pop Music

  • それ以外だと、去年の夏頃に山口県YCAMという文化施設のWebサイトのリニューアル・プロジェクトに参加したりしました。(→参考記事
  • そんな中、プログラミングは趣味として、2013年の春頃に始めました。そして同年夏からPerl入学式に生徒として通い始めて、翌年から生徒出身のサポーターとして活動に加わっています。
  • だから、というわけでもないですが、この記事で想定している「プログラミング入門者(初心者)」は、とくにITの仕事をしているわけでも、それを志しているわけでもない、「一般人だけど趣味で始めてみた」というような人です。
  • よって、IT企業の新人さんや、そうした進路を検討している情報系の学生さんなどはちょっとズレますが、部分的には参考にしてもらえるところもあるかもしれません。
  • また、上記のような初心者に「教える立場」の人にも、参考になる要素があるかもしれません。

Contents

1. 明確な目標はなくてもいい

  • 少なからぬ書籍やネットの記事において、「まずは学習を始める前に、プログラミングでどんなものを作りたいか、具体的にイメージしてみよう!」なんてことが言われます。
  • その心はと言うと、「目標が曖昧だと何をやればいいかわからなくて、無為に時間が過ぎるから」とか、「ゴールがはっきりしていれば必要な学習内容に集中できるから」ということのようですが、そこまで聞いても、ぼくにはこれは奇妙な方針だと思えます。
  • もしあなたの目の前に、初めて見る精巧な機械をポンと置かれて、「使い方は後で教えるから、まずはこれで何を作りたいか具体的にイメージしてみよう!」と言われたらどう思うでしょうか?
  • プログラミングの初心者とは、プログラミングに関する知識がない(または少ない)人ですから、まだそれを教わっていない段階で、「それを使って何ができるのか」を想像させるというのは矛盾があります。
  • しかし現実には、そうした要求をする「教える人」が少なくないように見えます。なんでだろう? と以前は不思議に思っていましたが、これはおそらく、「教える側にとって都合がいいから」ではないか、と今は思っています。
  • たしかに生徒さんの方から、「ぼくは掲示板を作りたい! Twitterアカウントでログインできて、画像も投稿できるようにしたい!」などと具体的なリクエストを言ってくれれば、「なるほど、じゃあそのためにはこの言語を覚えて、この知識を身につけて……」という具合に、何を教えたらいいのか、自然と決めやすくなるかもしれません。
  • 一方、「いや〜……とくに何を作りたいとかはないんだけど、とにかくプログラミングをやりたいというか……」などとぼんやり言われてしまうと、教える側としては、提示できる選択肢が無限に広がってしまい、「もう少し具体的に注文してよ!」という感じになってしまうのかもしれません。
  • しかし上記のとおり、初心者が知っている「プログラミングで実現できること」なんていうのは、「ない」か、あってもせいぜい数種類しかないはずで、しかもそのなけなしの選択肢ですら、本人が「本当にやりたいこと」かといえば、怪しいものだと思います。
  • ぼく自身のことを振り返ってみると、最初に「プログラミングをやりたい」と思ったときに頭にあったのは、「黒い画面になんか打ち込みたい」とか、「英数字でカッコよく構成されたあれ(ソースコード)を書きたい」みたいなものでしかなかった気がします。
  • それは「先に作りたいものをイメージしよう」と助言してくれる人が期待する答えからは程遠いものかもしれませんが、それでもぼくが一番求めていたのは、そんな曖昧で、とらえどころのない憧れのようなものだったと思います。
  • 「作りたいもの」なんてなくても、プログラミングの学習はできます。後述のとおり、すぐに(最短ルートで)求めるものに出会うことはできないかもしれませんが、続けていれば必ず、どんな曖昧な憧れであっても、近づいていくことができます。
    • 少なくとも、ぼく自身は入門から3年半が経った今、かつて思い描いていた上記のようなことは普通にできるようになりました。
    • 一応責任をもって、「作りたいものがなくてもプログラミングの学習をスタートする方法」を示しておくと、「入門書を読みながらサンプルコードを動かしていく」という方法があります。Rubyなら「たのしいRuby」、Perlなら「かんたんPerl」か結城浩さんの入門書、Pythonなら、未読ですが「独習Python入門」あたりが良さそうです。
    • もし希望する言語がないのであれば、上記のようなプログラミング入門書の中で、一番表紙の雰囲気が好きなものにするといいと思います。
    • 動画サイトの「ドットインストール」も良い選択肢だと思います。無料ユーザーにもたくさんのコースが開かれているので、明確な目的がない入門者でも自分の好みに近いレッスンを選びやすいですし、動画1本につき3分なので、ちょっと試して合わなければすぐ次を試したり、スキマ時間に気軽に始めたりすることもできます。
  • 念のために付け加えておくと、初めから「プログラミング自体は目的ではなく、自分のやりたいことを実現するための手段である」と、明確に目標を意識化できている人は上記の限りではありません。
  • また、すでに初心者的な段階を終えて、「プログラミングでどんなことができるのか」ということをある程度想像できる人であれば、「先にゴールを定めてから学習に取り組む」という方法も有効かもしれないと思います。

2. エラーは無理に読まなくていい

  • プログラミングの入門初期には、「本やネットに書いてあるとおりに実行しているはずなのに、想定されたとおりの挙動をしない」ということが多々あります。
    • 熟練者でもそういうことはあるようですが。
  • そのようなときに、入門者はコンソールに出てくるエラーをろくに読みもせず、自分で書いた(あるいはコピペした)コードをじっくりまったり読み返しては、何度も同じエラーを出し続ける、ということがよくあります。
  • そしてこのとき、教える側の人は、「エラーメッセージをちゃんと読んで」と言います。これはまったく正しいアドバイスで、その点に文句はないのですが、そのアドバイスが果たして有効に働くのかと言えば、あまり有効ではないとも思います。
  • 初心者にとって、コンソールに出てくるエラーというのは、もはや文字ですらない帯状の模様です。
  • その中のどれが英語で、どれが数字か、という見分けさえすぐにはつきません。
  • もし初心者と熟練者が、同じエラーメッセージを同時に覗き込んでいたとしても、両者が見ているのは別物です。おそらく熟練者は、「行番号」や主要な「キーワード」を真っ先に見つけているはずですが、初心者はそのメッセージにおける「どの単語がどの単語より重要なのか」という語句同士の優先順をつけることができません。
  • また、普段からプログラミングをしている人は、エラーメッセージが出てきた時点で、「またコイツか……」とばかりに「以前にそれを見たときのこと」を思い出したり、それが初めて見るエラーメッセージだったとしても、かつて経験したエラーを元に新たな原因の「仮説」を立てたりしているはずですが、初心者にはそうした「過去に経験したエラー」の蓄積が少なく、経験したとしてもすぐに忘れてしまうので、毎回メッセージの行頭から、見慣れない文言を一つひとつ読み解いていかなくてはいけません。
  • さらにまた、「初心者はエラーメッセージが英語だから読みたがらない」ともよく言われますが、ぼくは「英語」はあまり関係ないと思っています。
  • もし「Undefined subroutine ..」の代わりに、「指定されたサブルーティンが定義されていません」と丁寧な日本語が出てきたとしても、経験の浅い初心者には英語と同様の難解さがもたらされるでしょうし、その日本語が理解できるなら、英語であってもほとんど理解できるはずです。
  • つまり、問題は英語の能力にあるのではなく、熟練者が過去のエラーの経験や、そのときの文脈を踏まえてメッセージを読んでいるがゆえにそれを解読しやすいのに対し、初心者はその文脈がわからず、「なぜエラーが出たのか?」という原因を想像できないために、エラーメッセージを「目に入れる」ことはできても、その意味するところを「読み取る」ことができないのだと思います。
  • そうした前提を踏まえつつ、ぼくが思うのは、「エラーメッセージなんて、慣れれば自然に見るようになる」ということです。
  • エラーメッセージは、プログラマーが離れたいけど離れられない悪友のような存在であると同時に、忌憚なく、しつこくミスを指摘し続けてくれる親友でもあるので、やがて自分が何をやっているのか理解しながらコードを書けるようになれば、進んでその声に耳を傾けるようになるはずです。
  • 逆に言えば、苦しい思いをしてまでエラーを読んで、プログラミングに忌避感を抱いてしまうぐらいなら、気が済むまで何度でも、それを見慣れて頭に染み込むまで、同じエラーを吐き出させ続ければよいのではないかと思います。
  • ここでも一応付け加えておくと、これは「初心者にエラーを読めとか言ってはいけない」という話ではありません。むしろ読むように言うべきですが、ただ、もしあまり積極的にエラーを読まない初心者がいたとしても、それは怠慢や指導者への反抗心によるものとは限らなくて、上記のような理由があるからかもしれない、そのように思えれば、無用な軋轢を避けることもできるのではないか、みたいな話です。

3. 先生が間違っているかもしれない

  • このアドベントカレンダーの本体である「Perl入学式」は、プログラミングの初心者(またはPerlの初心者)に、無料でプログラミング言語Perlを教える有志による講座ですが、講義に使用する資料(教科書)もすべてメンバーがイチから作成しています。(→今年の資料
  • ぼくもその作成者の一人ですが、メンバーの中に職業としてプログラミングの講師をしている人は一人もおらず、みな自分の仕事の合間に時間を持ち寄って取り組んでいるので、残念ながら(というか)、資料中の不備や間違いも絶えません。
  • 一方、講義を受講する生徒さんにとって、ぼくたちスタッフはいわば「先生」ですから、基本的には「間違っていない」ことが前提になります。
  • よって、資料の中に誤記や、意味の通らない説明、問題文などがあっても、生徒さんによっては「わからない自分のほうが悪い」と思ってしまい、実際には教える側のミスなのに、それに気づかないまま少なからぬ時間を過ごしてしまう、ということも起こりがちです。
  • そしてこのようなことは、じつはプロが作った入門書や技術書でも起こることで、たとえば本の途中から、それまでに一度も説明していない用語や概念を使って話を進めてしまい、それ以降は読者を置いてけぼりにしてしまうような本もよくあります。
  • 商業出版物でもそんなことが起きてしまう理由には、そうした技術書が必ずしも「執筆のプロ」によって書かれているわけではない、ということがあるのではないかと思います。
  • 小説家や評論家、あるいは各種のメディアに寄稿する本職のライターなどは、みな執筆のプロですが、プログラミングなどを扱う技術書では、執筆で生計を立てているわけではない、それぞれの専門的な分野で活躍する人が文章を書く、ということが多々あり、それは言い換えると、「執筆のプロではない人が執筆している」という状況です。
  • 言うまでもなく、そうした状況が悪いわけではなく、そうでなければ生まれなかった名著も数え切れずあるはずですし、むしろそのような「執筆のプロではない人が書いた良書」を生み出すために、「編集者」と言われる人々が読者と執筆者の間に入り、わかりづらい表現や各種のミスを修正して回るわけですが、とはいえ、編集者にできることにも限りがありますから、やはり書き手が執筆のプロであるかどうか、という点はどうしても影響してくるところだろうと思います。
    • ちなみに、個人的に思う「執筆のプロ」とそうでない人の一番の違いは、「読者の視点で自分の文章を読めるかどうか」という点にあると思います。それは「読者に対する想像力」とも言えるもので、たとえるなら、幼稚園の先生が何人もの園児たちを引率して外を歩くとき、園児がちゃんと自分についてきているか、つねに振り返って確認しながら先頭を歩く姿に似ています。
    • ぼく自身はこのような、「読者がちゃんとついてきているかどうか」を想像しながら文章を書ける人が「執筆のプロ」だと思っています。
  • 話を戻すと、書店で売られている本だからといって、必ずしも安心して身を委ねられるわけではない、ということです。もし入門書などを読み進めているときに、よくわからない説明などに出会ったら、「自分が悪いはず」と思いすぎず、「この著者の表現がわかりづらいのではないか?」と疑ってみることも必要だと思います。

4. 最短ルートはないけど遠回りもない

  • よく経験者からの助言で、「自分はAの勉強より先にBの勉強をしていたから、効率がよかった」とか、「私は間違ってAの勉強から始めてしまったけど、時間の無駄だった。Bからやればよかった」といったふうに「学習の最短ルート」を示すような話を聞くことがありますが、ぼくはこういう話はちょっと怪しいと思っています。
    • 上記の「A」「B」には、「HTML」や「JavaScript」、「C言語」や「データベース」といったプログラミングの学習対象を適当に入れてみてください。
  • というのも、これがもし資格試験のように、過去の出題データをもとにして、その後の傾向をある程度予測できる分野であれば、効率的な学習の最短ルートを分析したり、体系化したりすることも可能かもしれませんが、一度しかないその人の人生から導き出される「別の方法をとっていれば云々」というタラレバの話は、実際にはとくに検証されたわけでもない、根拠のない思い込みに過ぎない可能性があるからです。
  • もし、「Aが駄目だったからBを試したらうまくいった」という人がいたとしても、それはもしかすると、「先にAを試したことが助けになって、その後のBがうまくいった」のかもしれませんし、いずれにせよ、その人が時間を遡って、他のすべての条件を同一に揃えて、別の方法を検証することは原理的に不可能です。
  • さらに言えば、100人の学習者がいれば、100通りのスタート地点があり、100通りのゴールがあるはずです。仮に、誰かにとって最短ルートの方法が見つかったとしても、それが他の人にも同様に作用するかと言えば、そのような保証はどこにもありません。
  • つまり、学習において、事前にわかる最短ルートなんて存在しないということです。
  • と同時に、最短ルートがないということは、遠回りもない、ということです。それが無駄な努力だったなんて、証明できる人はいません。
  • 学習というのは、続けるかぎり能力が向上するものだとぼくは思います。その「能力」の定義は時間の経過とともに変化するかもしれませんが、途中でやめてしまわないかぎり、その成果は生まれ続けるはずです。
  • というか、途中でやめてしまってすら、無駄になるとは言えないでしょう。どうもプログラミングを学ぶことは、あたかも無条件に良いことであるかのように語られがちですが、「やってみたらあまり興味を持てなかった」という人がいてもそれはそれで自然なことですし、そういう場合には、もっとその人に向いたことに自分の人生を費やすべきかもしれないですから。

5. 自分に合った方法は自分で作るしかない

  • 事前に考えていたトピックは上記の4点でしたが、最後にひとつ思い出したので、それを書いて終わりにします。
  • ここまでに書いてきたことも含めて、基本的に他人が示してくれる方法というのは、ユニクロで売っている既製服のようなものです。
  • ユニクロは、あなたの体型に合わせて服を作っているわけではありません。人間の体型を数種類の「大体のかたち」に分けてそれを作り、お客さんはその中から「自分の体型に近い服」を買っています。
  • 他人が示してくれた学習の方法は、世界に一人しかいないあなたのための方法ではありませんから、うまく機能しないこともあるでしょう。
    • むしろ、機能しないことばかりかもしれません。
  • これは学習に限らないと思いますが、自分のパフォーマンスを最大限に発揮するには、既存の方法を参考にしながらも、最終的には、自分だけにフィットした、オーダーメイドの方法を作る必要があるのだと思います。
  • その方法は、他の人にはフィットしないかもしれませんし、もしかするとほんの数ヶ月後のあなたにすらもう合わないかもしれませんが、「今までいろいろ試したけど、どうしても長続きしなかった」という場合には、この考え方が役立つかもしれません。

  • 本日の記事は以上です。
  • 明日のアドベントカレンダーは、吉祥寺.pmの主宰でもある@magnolia_k_さんです。
  • 今年のPerl入学式 Advent Calendarは、例年に増して多彩な人たちが参加していて面白いので、ぜひお楽しみください。

qiita.com

Gitでブランチ名を入力補完する方法がわかった

ここ数日、Perl入学式の講義資料を修正する作業をやっているのだけど、

  • 公式サイト

www.perl-entrance.org

GitHub - perl-entrance-org/workshop-2016

  • 作業風景


工程としては、そのリポジトリを手元にcloneして、ある程度のまとまりというか、修正の種類ごとにブランチを切って、それぞれ手を入れた後にコミット&プルリクしていく、というもので。

しかし普段、ぼくのGit用途ってとくにブランチを切る必要もないことばかりなので、そのブランチ間を移動するっていう経験じたいあまりなく、それゆえ、たまにやるとついブランチ名を長くしてしまって(一意になるように)、しかしディレクトリ移動時のように途中まで打ち込んでからタブを打っても入力は補完されず(当然)、ぐむむ……と思いながら地道に手で打ち込んでいた。

さらにしかし、今回はその修正対象がけっこう多岐にわたったこともあり、ブランチの数やその名前もどっと増えてしまったので、さすがにこれはツライ……とTwitterにとりあえずそのストレスを呟いて気を落ち着けようかと思ったのだけど、よくあるパターンとして、そうすると誰かが「こんな方法があるよ」と教えてくれたりするので、そこまでわかっているならそのやり取りも省略して自分で先に調べよ……と思って検索したらすぐに見つかって問題が解消した。

まず参考になったのは以下で、
qiita.com

内容は短いのだけど、ようは以下のリポジトリを紹介していて、

bashを使っているなら、その中のbash用ファイルをそのファイル冒頭に書かれているとおりに設置&設定すればいい。

.bashrc

source ~/.git-completion.bash

ちなみに、同リポジトリにあるプロンプトをいい感じに設定できるシェルスクリプトもなかなか素敵で、ついでにそれも設定しておいた。

source ~/.git-prompt.sh
before
PS1='[note103] \W\$ '

f:id:note103:20161204130157p:plain

after
PS1='[note103] \W$(__git_ps1 "->%s")\$ '

f:id:note103:20161204130207p:plain

閑話休題

しかし、実際に設置してみたものの、なぜか肝心のブランチ名の補完がきかない。
慣れない作業なので、設定方法を間違っているのかとしばらく調べたがわからず、検索しなおしたら以下の記事にぶつかって、

blog.basyura.org

一部引用すると、

alias g='git' と定義していて常に g と打っているのだけど補完が効かなかったので git-completion.bash をいじったら動いた (正しいのかは知らない)。

  __git_complete git __git_main
+ __git_complete g __git_main
  __git_complete gitk __gitk_main

とのこと。なるほど……エイリアスを設定していると動かないってことか?

たしかにぼくは git checkout のエイリアスを gco にしていて、gco と打った後にそのブランチ名が入らないなあ、と思っていたので、たぶん上に引用した箇所で、__git_main と同等の、git checkout にあたる変数を見つけて同様に記載すればいいのではないか、と思ってファイル内を検索してみたら、それっぽいのがあったのでこのようにしてみたところ、

  __git_complete git __git_main
  __git_complete gitk __gitk_main
+ __git_complete gco _git_checkout

補完されるようになった。

f:id:note103:20161204000808g:plain

これで一気に労力が軽減され、本質的ではない入力作業にかける時間を人生から削減できた。便利だし、ありがたい。

毎度のことだけれど、こうした知見をネットに書き残してくれている先人に感謝。

大抵のことはとりあえず呟いてみればなんとかなるものだが、今回は呟く前に解決し、解決してから呟いた。

最近買った技術書: CとC++

長らく続いたプロジェクトがひと段落し、先週末にようやく髪を切りに行った。

前回行ったのはまだ暑い7月か8月で、さすがにどうかという状況だったが、幸いというか何というか、とくに人と会う仕事でもなかったのでずっと放っておいたのだった。

その帰り、いつも髪を切った後に寄る三省堂で気晴らしの雑誌類と一緒に買ったのが以下の2冊。

新・明解C言語 ポインタ完全攻略

新・明解C言語 ポインタ完全攻略

スラスラわかるC++ (Beginner’s Best Guide to Programmin)

スラスラわかるC++ (Beginner’s Best Guide to Programmin)

前者はC言語の入門書等で有名な柴田望洋さんのけっこう最近出た本の模様。
(と言いながら奥付を見てみたら今年の8月だった。超最近)

この日はとくにC言語の本をほしいと思っていたわけではなかったのだけど、ちょうどここ数ヶ月、時間のあるときは以下を読んでいて、

なかなか集中できないものの、内容は面白い、わかりやすいなあ、と思っていたので、それのアップデート版的なものとして、説明や理解を補完するものとして買ってみた。

後者のC++本は、以前に読んだ以下の記事で名前が出ていたもので、

ascii.jp

こちらの著者の矢沢久雄さんも本当に読者のことを想像したわかりやすい文章を書く人で、その人の書く入門書なら読んでみたい、という感じで買ってみた。

これまたべつにC++に特段の興味があったわけではないのだけど、上記の望洋さんの本でもけっこうCとの比較でC++が出てきたりするので、何となくいい機会かと思ったのと、あと単純に今後何かプログラミングをするような場合に、現実的にCよりもC++に触れる機会の方が多いのではないか、だったら少しでも知っておいた方がいいのではないか、みたいに思ったというのもある。

ちなみに、じつは同書については以前電子版でサンプルを読んだことがあったのだけど、リフローではない固定型だったり、サンプル部分が短く感じられたりして内容以前にフォーマットの問題として読みづらいな・・と諦めたことがあったので、今回紙版であらためてトライ、というのもあった。

で、逆にというか同じスラスラわかるシリーズでもC言語を扱った以下の本があって、

スラスラわかるC言語 (Beginner’s Best Guide to Programmin)

スラスラわかるC言語 (Beginner’s Best Guide to Programmin)

これは以前に電子版を購入して通して読んだのだけど、感想はこんな感じ。


なんというか、絶賛。
いや本当に面白かったし、わかりやすかった。

こっちの方は電子版もちゃんと(というか)リフローだし、結構ことごとく読みやすく作られているように感じた。

まだ上記のC++の方は初めの方を読んだだけだけど、同じシリーズだからかキャラクターやイラストやフォーマットは同じようでいて、じつは各キャラクターのキャラクターというか性格というか、セリフの雰囲気などは著者ごとに違っているようで、たとえば岡嶋さんの本における各キャラクターは毒舌系というか、やけにハイコンテクストで時にハイコンテクストすぎないか、いや自虐的すぎないか、といったことが気にならなくもなかったけれど、それも含めて非常にオリジナリティにあふれた面白さがあった。

この岡嶋さんの本についてはすでにこのブログでも紹介したと思っていたけど、検索したら無かったのでついでのようだけど触れておいた。

bcコマンドで電卓計算(小数の)

ちょっとした数字の計算をしたい、けど電卓出すのは面倒……ということがよくある。

ぼくはちょっと前まで簿記の勉強をやっていたので、マイ電卓がすぐ手の届くところにあるのだけど(一番体に近い引き出しの中)、そこから出すのすら面倒、と感じてしまうことが多々ある。

その一方で、両手はつねにパソコンのキーボードに置かれているので、ターミナルにパパッと打ち込んで計算が済むならそれがいい。

ということで、今まではそういうとき、ターミナルでirbとかPythonとか、最近だとPerl6を立ち上げたりしていたのだけど、たまたま何かの作業中に間違えて bc と打ったらコマンドが起動して、そのままちょっと動かしてみたら電卓だった。

f:id:note103:20161019025613g:plain

なにこれ便利。

なのだが、どうも小数点の計算ができない。
具体的には「5 / 2 = 2.5」とか。

f:id:note103:20161019025633g:plain

どっちかを小数にすればいいのか? と思うも……

f:id:note103:20161019030316g:plain

そういうことでもないらしい……惜しい。

しかしながら、経験的にたぶん、こういうのはちょっとしたワザを使えば案外普通にできるはず。
と思ってあちこち検索してみたところ、結論的には scale というのでケタ数を指定すればいいようだった。

f:id:note103:20161019025651g:plain

整数値がゼロの場合は画面に出てこない(小数点から始まってしまう)が、まあよし。

なぜかこの、scale で指定すればいい。というだけのことがなかなか上記の検索でうまくヒットしなかったのでブログにメモしておいた。

ちなみに、その検索過程で echo からパイプでつなげてやる方法も知ったが、

$ echo "scale=1; 5 / 2" | bc
2.5

上記のぼくの用途だと単に bc と打つだけの対話型のほうがラクだと感じる。

Perlにおける日本語文字化け対策の私的まとめ

Perlで日本語のテキストを処理しているとけっこうな割合で文字化けにハマる。
近いことについては以前ここでみっちり書いたが、
note103.hateblo.jp
どうもその後、自分はbinmode関数やopen関数、およびutf8やopenプラグマについて理解が怪しいな、と思ったのでいろいろ調べつつ現時点での認識をまとめてみる。

環境づくり

まずはサンプルケース的に、文字化けしがちな状況を作る。

素材データとして、以下の内容をエンコーディングUTF-8のテキストファイルにsource.txtという名前で保存。

りんご
hello

1234
ネコ

次に、そのデータをopen関数で読み込み、split関数で切り刻んで標準出力および書き込み用ファイルresult.txtへ書き込むPerlスクリプト「openio_stdout.pl」を書く。

#!/usr/bin/env perl
#
# openio_stdout.pl

use strict;
use warnings;
use feature 'say';

use utf8;
use open IO => qw/:encoding(UTF-8)/;
binmode STDOUT, ':encoding(UTF-8)';

# 1. 素材データ読み込み
my $in = 'source.txt';
open my $fh, '<', $in or die $!;
    my @data = <$fh>;
close $fh;

# 2. いろいろ処理
my @out;
for (@data) {
    my @split = split//, $_;
    for my $s (@split) {
        push @out, "字$s";
    }
}

# 3. 処理済みデータを書き込み
my $out = 'result.txt';
open $fh, '>', $out or die $!;
    print $fh @out;
close $fh;

# 4. 標準出力に出力
print @out;

実行。

字り字ん字ご字
字h字e字l字l字o字
字犬字
字1字2字3字4字
字ネ字コ字

素材テキストの1文字ずつの間に「字」を入れてみた。
これが書き込み先のresult.txtにも、標準出力(ターミナル)にも出ている、という状況。

つまり、この時点では文字化けしていない。が、それは冒頭にある以下の宣言がちゃんと動いているからで、

use utf8;
use open IO => ':encoding(UTF-8)';
binmode STDOUT, ':encoding(UTF-8)';

これを誤るとけっこう盛大に文字化けする。
以下、それを順に見ていく。

utf8プラグマ

まず、今回の例ではソースコード内に日本語の文字(「字」)を入れているので*1、最初のutf8プラグマが必要になる。

use utf8;

もしこれをコメントアウト等で無効にすると……

f:id:note103:20160925140246p:plain

こんな感じになる。
標準出力でも、書き出しファイルでもこうなる。

utf8プラグマというのは、この例における「字」のように、ソースコード内に素材となる文字を直接書いたとき、それをPerlで処理するための「内部文字列」に変換してくれるもの。

内部文字列に変換されなかったらどうなるかと言うと、Perlがそれを「なんか文字じゃないもの」ぐらいにしか扱ってくれず、上の画像のように化けてしまう。

ちなみに、この「内部文字列に変換されなかった何か」のことは外部文字列……とは呼ばず、「バイト列」と呼ぶことが多いらしい。

で、ここではそのコード内に直接書かれた「字」をutf8プラグマの宣言によって「内部文字列」に変換している。

openプラグマ

次に、このコードではファイル入出力(source.txtを読み込んでresult.txtに書き込む)をやっているので、2番めのopenプラグマも必要になる。

これは別解として、各open関数の第2引数でこのように書いても良いようで、

open my $fh, '<:encoding(UTF-8)', $in or die $!;
(略)
open $fh, '>:encoding(UTF-8)', $out or die $!;
(略)

それを冒頭のプラグマでまとめて宣言している。

また、このプラグマ部分はこのように分けて書くこともできるが、

use open IN => ':encoding(UTF-8)';
use open OUT => ':encoding(UTF-8)';

今回はIN/OUTの両方をやってるのでIOというレイヤーでまとめている。
と同時に、IOなら省略してもOKらしい。

use open ':encoding(UTF-8)';

で、さっきのutf8プラグマは元に戻して、このopenプラグマだけ無効にするとどうなるかと言うと、こうなる。

f:id:note103:20160925140639p:plain

このうち、上側の

Wide character in print at /Users/kadomatsuhiroaki/open/openio_stdout.pl line 29.

というのは標準出力(ターミナル)に出るもので、書き出し先のファイルには出てこない。

その下の文字化け部分は、標準出力と書き出しファイルの両方に出ている。
不思議なことに、というか特徴的なこととして、一つ前の文字化けでは文字間に挟んだ「字」が化けていたのに対し、今度は「字」だけが普通に表示されている。

この段階ではutf8プラグマが生きていて、openプラグマを止めているのでそういう生死の違いが出るのだろう。

また、openプラグマの引数「:encoding(UTF-8)」は、「:utf8」と書いてもほぼ同等の働きをするようだが、前者はデータの入力時にそれが正しいutf-8かどうかをチェックするのに対し、後者はそうじゃないらしいので少なくとも入力時はあまり省略しないほうが良さそうである。

binmode関数

最後に、binmode関数。じつはこれが今まで一番わかっていなかったのだが、どうもいろいろな現象や解説書を並べて観察してみると、単に(というか)標準入出力時にその対象となるデータの文字コードを指定するもの、と考えれば良さそうである。

今回はデータをファイルから入力して、ファイル&標準出力に出しているので、STDOUT時の文字コードのみをbinmodeで指定している。

binmode STDOUT, ':encoding(UTF-8)';

例のごとく、これだけコメントアウトしてみると……。

f:id:note103:20160925140820p:plain

さっきと同じ。……かと思いきや、また微妙に違っていて、まず以下の対象行番号が29から33に変わっている。

Wide character in print at /Users/kadomatsuhiroaki/open/openio_stdout.pl line 33.

ではこの二つの行がソースコード上のどこにあたるかと言うと、以下の部分における、

# 3. 処理済みデータを書き込み
my $out = 'result.txt';
open $fh, '>', $out or die $!;
    print $fh @out;
close $fh;

# 4. 標準出力に出力
print @out;

前者のprint文が29行目で、最後のprint文が33行目。

つまり、openプラグマはopen関数内のprint文に効いていて、binmode関数の方は標準出力時に影響していることがこれらの情報から見てとれる。

また、肝心の本文のほうも、前者は文字化けしているが後者はしていない。
ただしこれは、ここで問題にしているbinmode関数の有無による違いではなく、ひとつ前の例でopenプラグマをコメントアウトした際、入力レイヤー(IN)も外してしまっているために、前者では文字化けが生じていると考えられる。

試しに、一つ前の文字化けはこのような状態で生じたが、

# use open IO => ':encoding(UTF-8)';
binmode STDOUT, ':encoding(UTF-8)';

このように、その状態からopenプラグマの入力レイヤーだけを復活させると、

use open IN => ':encoding(UTF-8)';
binmode STDOUT, ':encoding(UTF-8)';

文字化けは解消する。
(と言いつつ、たしかに文字化けは消えるが今度はbinmode関数のみを無効にした場合とは少し異なるエラーが出てくる。つまり、それらはどれも異なる状態なのだが、これ以上の追求&説明はだいぶ大変なので割愛)

標準入出力もopenプラグマにまとめる

今回の研究というか勉強に際しては、以下3冊を繰り返し見比べては突き合わせ、読み返したが、

初めてのPerl 第6版

初めてのPerl 第6版

かんたん Perl (プログラミングの教科書)

かんたん Perl (プログラミングの教科書)

Perl CPANモジュールガイド

Perl CPANモジュールガイド

そのうちのCPANモジュールガイドで紹介されていた方法。

現在はこのようにしている2行を、

use open IO => ':encoding(UTF-8)';
binmode STDOUT, ':encoding(UTF-8)';

以下のようにまとめられる。

use open IO => qw/:encoding(UTF-8) :std/;

ようはbinmode関数で指定していたことをopenプラグマの引数に「:std」とすることで代替(というか)できる。

いま自分で書いているコードにおいては、同様のことをしたいときは基本最後の形にしている。

まとめ

日本語の文字化けについては常に悩まされるところだが、原因を追っていくとそれなりに明らかになってくるのが面白い。

エラーの内容も書き換えた部分によって変わってくるし、同じエラー・メッセージでもその分量(行数というか)が異なり、それがまたマシンの気まぐれなどではなく、異なるには異なるだけの理由がある。

面倒だ、ぐぬぬ、イライラする! と思うことも少なくはないが、それでも玉ねぎの薄皮を剥がすように少しずつマシになってきていると感じる。
そのような理解を助けてくれる上述の書籍、および知見に満ちた先達やネット上の各種解説記事に感謝します。

付録

今回の出力例の画像(黄色っぽいベージュっぽいやつ)について、本来ターミナルに出るような結果なのに行番号が出ているのはなぜだろう? と思われる人もいるかもしれないが、これはコードの実行結果をVimの同一ウィンドウ&分割バッファで表示してくれるプラグインquickrun.vim」を使って表示している。
github.com

ここでやっているような利用法については以下の記事でも触れたので合わせて挙げておく。
note103.hateblo.jp

*1:サンプルの文字選択を誤ったかもしれない。まぎらわしい。