トップ 最新 追記

日々の破片

Subscribe with livedoor Reader
著作一覧

2018-05-04

_ 丸美屋のアニー

子供が一昨年か一昨々年に見て来て、一緒に行こう、おもしろいよ、と言われていたアニーを観に新国立劇場。

箱は新国立劇場だが、丸美屋がスポンサーのようだ。

当然ながら子供が多いが良いことだ。

物語はうまくできていて、実に楽しい。子供を殺すことも平気な悪役は出てくるが、全体的に良い感じなのは、(子供が言っていたが)富豪を含め、みんな良い人だからだろう。

ミュージカルとしては良い舞台だし、作品だということはわかった。おもしろかったし、楽しめた。

が、内容はいろいろ思うところがある。

そもそもミュージカルでアニーと来たら銃を取ると思っていたくらいに知らなかったわけだが(子供にその時、違うと教わった)、なんとも、現代に通じる物語だなと思って後から調べたら、原作はオイルショックの頃で、スタグフレーションになっていた時代だ。そこからデフレになっていた世界不況期のアメリカを重ねたと考えられる(観ている間は赤狩りのころか、さもなければ日米貿易摩擦の頃に成立したミュージカルかな? と推測していた)。

というわけで、11年も父母から音沙汰がなく孤児院で暮らしているが希望を失わずに元気いっぱい、明るく、愉快で、人当たりが抜群な赤毛でソバカスの白人中の白人の女の子のアニーが、不況で工場を閉鎖し労働者を解雇することに悩む経営者や、ルーズベルト大統領と取り巻きの頭脳集団に対して、現状がどれだけだめでも希望を失わないことを教えて、強いアメリカを取り戻そうということがテーマになっている。

ただ、日本人を狙い撃ちで強制収容した差別主義者のルーズベルトはともかくとして、ここでの経営者が、初代だという点はとても重要だと思う。

貧乏のどん底から汚いことにも手を染めながらのし上がって来た男だけに、明日は我が身感に根差す真摯な弱者に対する共感があるからだ。これが物語に説得力を与えている。

したがって、アニーが友達をパーティーに呼ぶなら、まずは使用人のなんとかさんと……と言い出したときに、なるほどそれは良いアイディアだと同意して、友人のなんとかさんとして使用人たちを扱うのもおかしくはない。というか、とても自然な流れでパーティーを楽しいものにしている。

これがイギリスなら階級がそもそも違うから意味わからん、となって撥ねつけそうだ(それはそれで別のストーリーが生まれることになるだろう)。

あと、三代目もお話にならないだろう。そういうものだからだ。現在進行中だな。

(ふと思い出したいが、ゴッドファーザーでも初代のマーロンブランドは恐ろしい男だが人間的にはとても良いやつなのに、三代目のロバートデニーロは危険極まりない非人間として描かれていたなぁ。組織を作る立場と、組織を守る既得権益側だと同じ家族でもずいぶんと違うってのは万国でわりと共通なのかも)

犬とアニーのシーンでは、警官がやたらと人情味を見せるが、同じ警官が浮浪者に対しては職務に厳格に忠実なのが、いかにもありそうでおもしろい(主人公がアニーである必然だ)。

というわけで、30年代のアメリカを舞台に70年代のアメリカに対する応援歌を2010年代に日本で見ると、共通点はあるものの、根本のところが異なるので、なんか微妙な味わいがあった。


2018-05-06

_ 1789

帝国劇場で1789。

思い起こせば、忘れちゃったけど5年位前にかずひこさんにおもしろそうなフランスのCDを買ってもらったことがあって、そのときかずひこさんが選んだのが、モザールだった。

Mozart L'opera Rock / Ocr(Mozart L'Opera Rock / Ocr)

なんだこりゃ? と思ったらミュージカルで、筋書きはミロシュフォアマンのモーツァルトと同様にサリエリが嫉妬にかられてモーツァルトを追い詰める話になっているのだが、個々の曲がなかなか良い。

特にモーツァルトがパリで売り込みしているところの今晩君のベッドに連れてってという歌とか(そんな歌ないなと思ったら、入れ墨してくれ、という題だった)、ザルツブルクから逃げ出すときに歌う、通過点(スピード感があって、リベルテという言葉が実にかっこよく歌われる)が好きだが、それよりも、とにかくアニメ声の女声陣に驚いた。で、これが悪くないというか、積極的に好きだ。特にモーツァルトのお姉さんがレオポルトが死んだときに歌う私の天使眠りなさいとコンスタンツェのもしも私がしくじったら、が気に入った。

というわけで、この作曲家が気に入ったので、DVDで太陽王、1789、モザールの3枚組を買って見まくった。それにしても、女声陣、声はアニメ声なんだが、実際は妙に立派な女性(大人)でその落差にまたしびれる。

3 grands spectacles : 1789, les amants de la Bastille + Mozart, l'opéra rock + Le Roi Soleil

で、まあモザールはミロシュフォアマンもどきだし、太陽王はまったく興味がないので観ないで、1789ばかり観ることになった。なにしろ、パレロワイヤルを子供を連れてダントンがのし歩き、ロベスピエールがテニスコート(じゃないが)で踊りまくり、デムーランが銃を取れと叫ぶんだから、おもしろくないわけがない。

(パレロワイヤルをのし歩くダントン。肖像画に合わせてブ男だから子供と娼婦しか相手をしてくれないという設定になっている)

で、これまたマリーアントワネット、主人公の農民の妹(ダントンの恋人)、主人公と愛し合うルイフランソワの養育係にしてバスティーユ弾薬庫の警備隊長の娘(ご都合主義の設定)がアニメ声で歌いまくるわけだが、これも実に気分良い。

それにしても、なぜこうもアニメ声なんだろう? と不思議になるわけだが、子供に言わせると、フランス語は比較的舌先で発話する(あとは鼻に抜かす)のでアニメ声になりやすいのではないか、ということで、言われてみればおれが好きなLioも相当にアニメ声の歌手だな。

というわけで、作品が好きなのでよほどのことがなければ舞台を観てうんざりするわけがなく、当然のように楽しめた。それにしても、イケメンぞろいなのに、ダントンだけはメークのせいか美形ではないように扱っているのがちょっとおもしろい。シャルロット(ダントンと出て来て、そのあとは機械仕掛けの神のように振舞う謎の子供)役が実にうまくて良かった。あと、子供も言っていたが、ロベスピエールの踊りが抜群で、エーベルとの闘争(これは必要だったけど)とかダントンとの闘争とかせずに、ふつうに踊っていればテルミドールを招かなかっただろうなぁとか。

前回観たときは、マラーがマラーとして印刷所を切り盛りしていたような記憶があるのだが、今回はマラーはマラーとしては出てこなかった。が、全体的に台詞をいじったのか、ずいぶんとつながりがわかりやすくなっているように思えた(1789年に何があったか知らん人のほうが多いだろうからつながりを良くするのは重要だとは思う)。

それにしても、ルイ16世が錠前を作ってマリーアントワネットにプレゼントしようとしたり、半月形のギロチンの刃を斜めに改良したりとか、伝説的な史実をいろいろ入れてきているのも楽しい。

舞台的な演出としては、マリーアントワネットの登場シーンは素晴らしい(オリジナルの舞台より日本版のほうが素敵だ)。

というわけで、サンドニ寺院には天使が舞い降りる。

最後人権宣言を読み上げて幕。人権宣言は名文だとつくづく考える。舞台だと自然権の行使の箇所を他人に害を与えない限り何をしても自由のような言い方に変えている(途中、どこにもラファイエットは出てこないが主人公の学習の成果として何度も口にする)が本質的には間違っていない。

#パリの主婦によるパン屋襲撃のところに相似な構図を何かで見たか読んだかしたなぁと思って考えていたが、伊藤野枝が大阪の米屋襲撃事件に介入するところか(大阪の米屋と違ってパリのパン屋は小麦粉が実際にないのでパンを売れないという設定になっているが、本当にそうだったのかどうかはわからん)。

Music From: 1789, Les amants de La Bastille(Musical Mania)

(買っちゃた)


2018-05-12

_ 怪奇小説日和

MA2さんがFBでおもしろがっていたから、おれも買って読んでみた。ちくまもさっさと電子書籍出せ。

英国の20世紀初頭を中心とした怪奇小説(幽霊譚からサイコキラーものまでいろいろ)を集めているが、抜群なのはドン・ファン・グスマン・デル・プルガル、ミラモルの伯爵の永久墳墓での冒険を描いた七短剣の聖女(ヴァーノン・リーという人が書いた)だ。豪華絢爛な描写(いちいちドン・ファン・グスマン・デル・プルガル。ミラモルの伯爵と主人公の主語を書くところも含めて)が圧倒的に楽しい(というか、おれは人口楽園の描写が好きなんだな、と、先日観た空海の極楽の宴もすごく好きだったし、江戸川乱歩の末裔なのだろうか)し、最後の謎にどう答えるかのサスペンスといい、素晴らしい。この作品に比べてしまうと、ダポンテ・モーツァルトも相当にかすんでしまう(が、エルビーダが出てくるのでそこはおお、おなじみの名前だ、と楽しい。というか、ドンナアンナの名前が出てこないので、ドンナアンナと騎士長を巡る物語が始まるのかと思ったら、全然違った)。

列車もおもしろい。1950年初頭か終戦直後だと思うが、女性二人の微妙なハイカーの物語。最後、翻訳の問題かあるいは作者の曖昧描写のせいかはわからないが、2種類に解釈できる言葉が出て来るので(多分、婚約側だとは思うのだが)解釈は難しいが、そもそもはヘンリージェイムズのお国柄だ、すべては解釈できず、すべてを知ることもできない、ので、それで良いのだろう。という点からは陽気なる魂が抜群におもしろい(短いのもあって5回読み返したが、全然わからん。最初は輪廻するというか館にとらわれる物語かと思ったが、そうではなく立場の変化に過ぎないような気がしているし、単なる誤解の物語のような気もする)。もしかすると、加齢によって読解力が落ちたのかも知れない。その分、何度でも解釈し直せるので楽しいとも言える。

ターンヘルムはできの悪いヴァグナーみたいだが、ミーメの役回りがぷくぷくした感じが良い人で、ハグリットそっくり(というか、性格、容姿、行動、どう読んでもハグリットなので、ローリングがハリーポッターを書くにあたって引用したとしか思えない)なスティーブンスがおもしろかった。というか、ハリーポッターの原型に読めるんだよなぁどうあっても。

というわけで、英国人は気分が悪い連中で、怪奇小説を書かせたら世界でもっともうまい連中なのは間違いない(創元文庫の5冊組を読んで確信したことを再確認した)。

怪奇小説日和: 黄金時代傑作選 (ちくま文庫 に 13-2)(西崎 憲)

#1番の怪奇は、同じオチの作品があると書いてある解説で、どれだかわからない。多分。


2018-05-13

_ ネコ以外のネコ科は滅びの道を往く

妻がなんかテレビでチーターが走るところを観ていたので、途中まで一緒に観ていた(というか、妻は途中からいなくなった)。

チーターの筋肉の動きが実に美しい。子供はとても頭が丸くてかわいい。

どうもネコ科についての番組っぽい。

ヒョウがワニを仕留める。噛み付く力は200kg、自重は100kg近くあるのを、ヒョウは川に飛び込み脊椎を牙でくだき、血の匂いを嗅ぎつけて他のワニが攻め込む前に岸にひきずり上げて灌木の茂みまで運んでバリバリ食べる。

チーターがガゼルを追う。チーターの体重は40kgなのでガゼルくらいしか倒せない。子供も一緒にむさぼり食う。美しい。

ヌーを狩りする雄ライオン3人組。ライオン3人がかりでやっと仕留める。その間ヌーは一斉に逃げるが、1頭が襲われると逃げるのをやめてそれを眺める。2頭目は襲わないと知っているのだな。

ライオンのメスがチーターの縄張りに入ってくる。チーターの匂いがしたからだ。

ナレーションが入る。

匂いを嗅ぎつけてメスライオンはチーターの子供を殺しに来たのです。

考える。チーターの子供はヌーなんかと違って食べるエサとしては意味がない。それなのに殺すとしたら、同じく肉を食べる敵だから排除しようということだな。

ナレーションがライバルは、と続いたので考えが正しいことを知る。

チーターの母親はライオンのメスを挑発する。ライオンはチーターを追う。が、追いつかない。というか、本気でライオンは追っていないように見える。そこでチーターがまた近づく。何度も繰り返すうちに、雌ライオンは疲れたのかゆうゆうと引き返していく。が、母親に近づいてきた子チーターを一人噛み殺す。そして去っていく(確かに、まったくこれっぽっちも食べようとはしない)。

ナレーションが入る。チーターの子供が大人になるのは5%です。今見ているチーターの母親はもともと3人の子供を持っていた。今、残り60%となった。が、確率的には残りの2人も殺されて終わるわけだな。

どう見ても、肉食獣はわりに合わない。食べ物が極度に限定されているからだ。ヌーの余裕っぷり(いちおう、かたちばかりは逃げるが、1頭食べさせるとあとは高みの見物態勢になるし、近くにトムソンガゼルが来ても別に気にもしていない)に比べてせせこましい。

それにしても、チーターが体をしならせて走り出す姿があれほど美しいものだとは知らなかった。


2018-05-20

_ バロッサのカレーペーストが美味しい

四谷の丸正に行ったら、やたらとBAROSSAのカレーペーストというのを押していて、つい買ってしまった。

なんか、ぱっと見はレトルトカレーに見えたが、パウチされたペーストだった。まあ、それはそれでありか。

で、買って作り方見ると、鶏肉と生クリームとか書いてあるから、それも買って、玉ねぎいためてペースト混ぜて、水600cc(1パウチで4人分くらいという量)入れたら、真っ赤になった。すげぇ辛そうと妻がびびるが、食べてみたら見た目ほど辛くはない。というか、本気で辛ければ、パッケージにもそう書くだろうが、別に辛いとも甘いとも書いてはなかった。

ふと気づくと、仕上げの生クリームを入れずに、ばくばく家族で食いまくってえらく満足した。

というか、とてつもなく美味しい。

レストランの味! というパウチのカレーソースとしては、これまでDELI一択と思っていたが、おれはバロッサのほうが美味しいと思う。

というわけで、どういう仕入れしているのか知らんが、1回こっきりの様子見だったらやばいので、丸正に行って、しこたま買い占めた。

が、良く見ると、2階の肉コーナーの脇(丸正本店は古びたビルなので、なんか汚くみえてあまり好きではないのだが、扱っている商品(高級過ぎて買えない魚(竜宮の遣い2万円とか。あー食って見たかったが、価格が価格なので買ってうまくさばけるとは到底思えないし(手がふるえちゃうよな)そもそもどうやって食えば良いかもわからん)とか牛肉とかもある)といい、陳列といい、えらくうまい)だけではなく、1階の普通のカレーソースコーナーにも置いてあったりして、単に押しまくっているだけだとわかった(特設コーナーだけなのかと思った)。で、大量買い占めを、適度な買い占め程度に抑えることにした。

それにしても、これは美味しいと思って、さてバロッサってなんだ? と(デリーとかナイルとかと違って、ずいぶんと新参だよな? と)調べたら、カレー専門店ではなくて、それも驚きだった。

バロッサ(食べログ)


2018-05-22

_ 現時点で最もRailsの美点と感じること

db:migrate

――これに尽きるのではないか。

というか、コードのリファクタリングは(テストのことはちょっとおいておくとしても)すさまじく低コストにできるのだが、リレーションのリファクタリングはとてつもなく高コストなはずなのに、db:migrateによってえらく低コストになっている(と実感している)。

すでにインスタンスを永続化していても、タスクをちょろっと書いてrakeを流せば済むようにフレームワークがあるので実にお気楽にできる。

これはとんでもないなぁ。

・結果的にデータモデルを多少バータリーに決めても、後で軌道修正が無茶苦茶簡単にできる。

_ 複数のリレーションと1対多でリレーションシップを持たれるリレーションをどうActiveRecordで実現するか

例としてタイヤのテーブルと、自動車のテーブルとオートバイのテーブルがあり、自動車用のタイヤもオートバイ用のタイヤも同じタイヤテーブルで管理しているとする。

自動車はタイヤを持つし、オートバイもタイヤを持つ。

一方、生産年度というかロットでタイヤを管理することで、不良品のタイヤを履いている自動車やオートバイに対して通知をするような仕組みが必要とする。つまりタイヤ側からもオートバイや自動車に対してのリレーションシップが必要だとする。

ActiveRecordの楽ちんなhas_manyとbelongs_toを使いたいというのは大前提だ。

とすると、自動車 has_many タイヤであり、オートバイ has_many タイヤなのは当然としてタイヤ側にとってはbelongs_to 自動車であり belongs_to オートバイなんだが、これは嬉しくない。

なんで嬉しくないかといえば、商売を広げて飛行機が出てきた場合、飛行機 has_many タイヤとして、タイヤ belongs_to 飛行機を追加するのか? ということになる。

いくらmigrateが簡単とは言え、こんな調子でばかばかタイヤに自動車_idとかオートバイ_idとか飛行機_idとか追加するのはあり得ない設計だ。

というわけで、代替案を考えると、ActiveRecordの仕組みを使った素直な実装は、STIで共通テーブル(乗り物大集合)に対して自動車やらオートバイやらのサブセットを定義することだが、おれはイヤだ。いくら方便とは言え、実装は全部入りスーパークラスの部分集合で具象クラスを表すというのは、オブジェクト側がまともに見えても下品だと感じる。

具象の世界でいえば、タイヤテーブルになんちゃらidをどんどこ追加するのがイヤというのが最初にあるわけで、同じようにウルトラスーパーな乗り物にあらゆる乗り物の属性をぶち込むなんていうのが許容できるわけがない(具体的な作業においては必要に応じてカラムをばんばん追加してどんどこdb:migrateすれば良いだけなので作業負荷はほとんどない。つまり、そんなにまずくはない。こうなると美意識の問題としか言いようがない)。

で、IOのオーバーヘッドに目をつぶれる程度のhash_manyしかないということから、has_many throughを使って、自動車とタイヤのジョイントテーブル、オートバイとタイヤのジョイントテーブルをそれぞれ作って、タイヤは何もhasせずに、ジョイントテーブルがそれぞれに対してbelongs_toし、自動車やオートバイはそれぞれの専用ジョイントをhas_manyするようにした。本物の乗り物であればジョイントというよりはサスペンションだな。

# パフォーマンス的には最悪の選択だが(STIに比べてアクセスは倍増する)、抽象モデルと具象モデルのバランスとしては、この例の場合については、おれにはhas_many throughが最も良いと感じる。パフォーマンス重視であれば(何しろアクセス倍増だから)、STIを使うべき局面ではある。というのはわかっている。


2018-05-24

_ そろそろ体制が変わる節目だ

牽強付会ではあるが(と最初に明言)、大体において人類の歴史では70~80年というのは節目で、大きく体制が変化する。

これは3代目理論によるものだ。

初代は強力な理念と運とカリスマによって混沌の中に新しい体制を作る。2代目がそれを保守する。3代目になると新機軸を打ち出そうとするか、あるいは惰性でどうにか継続させようとするがぐだぐだになって瓦解と混沌が始まる。で、どうにもならなくなって次の体制が生まれる。

年齢的には30~55歳くらいの中心人物が3代交代して75年というのが根拠となり(かっきりいくわけではないので、大まかには70年から80年というところに収斂するわけだが)、太平洋戦争前に、大日本帝国がこのままではまずいぞと「売り家と唐様で書く3代目」と放言した尾崎不敬事件が念頭にあったりはするが、3代目が唐様で書くのは尾崎の発案ではなく詠み人知らずの格言で、古来日本でもなんとなくそんな感じの歴史観があったという証左でもある。

(当たり前だが、下部構造のほうが大きいので、人間の直系3代というように収まるわけはない)

もちろん、日本で体制が大きく変わったのは1946年だから、70を足せば2016年で、そういう体制瓦解期にはすでに足を突っ込んでいる(おれには末期に見えるが、始まっているように見たい人たちがいるのは知っている)。

1946年の前は1868年の維新、その前は1787年の寛政の改革で、旧体制の田沼をみんなが懐かしむくらいに様変わりして近代へ突入した時代だ。

そも前は1680年代後半あたりからの元禄時代の始まりで市民文化の始まりである。明確な区切りがなく始まるのが市民文化というところだ(その分、寛政の改革は完全なる別体制の始まりらしくかっちりとしている)。この期は中心人物がばらけているので100年近くもったというか混沌としている。

もちろん、その前が幕府開闢1603年。その前の区切りは混とんとしているが鉄砲伝来1543年あたりとしよう(戦争のありようの変化の始まり)。

そして1467年が応仁の乱で多頭体制の始まり、1378年に花の御所で室町時代が本当に始まる。このあたりからは30歳~55歳の25×3の周期が25歳~45歳の20年くらいに縮まるので大体60年くらいで1体制となる。

他国へ目をやると、中国は1978年の改革開放-1912年の中華民国建国-1840年のアヘン戦争-(1760あたりを適当に埋める)-1681年(康煕20年の三藩の乱鎮圧により康熙帝の完全支配開始)というようになる。この区切りだと今の中国は皇帝元年というよりは、改革開放路線の爛熟期に突入した(過渡期の始まり)なのだろう。

というわけで、2020年のオリンピックの前後で、戦後民主主義レジームが終わり次が始まるわけだが、どういう方向に進むのか、興味津々だ(が、小泉だけは選ぶなよ)。


2018-05-30

_ ルイザ・ミラー(メトライブビューイング)

東劇でルイザ・ミラー。

最近えらく気に入っているソンニャヨンチョバがタイトルロール。

ルチアと同じで、当時のヨーロッパから見た未開の王国イギリス(スコットランドかもしれないけど、ドーバー海峡の向こう側)の野蛮人が封建領主の支配と圧制に苦しむ物語だということくらいしか知らずに見る。

村娘がルイザミラーの誕生日を祝うために家に押し掛けるところから始まる。

やたらと不吉だ不吉だと呪いを吐く、退役軍人のミラーさん(ルイザの父親)がドミンゴで、本当にメトはこの声が出ないむさいおっさんのこと好きだなと斜に構えて観ていたら、1幕の娘の結婚は本人の自由意志に任せるのであって父親だからと強制できるはずないだろの歌唱には驚いた(この歌は最初の「なんてこと言うんだ」からしてえらくかっこ良いが、後でシラーの作品だと知ってこれまた納得した)。この役については見事だし、咳で最後までまともに歌えなかったイルトロヴァトーレと違ってここでは声も通すし、悪くないどころか立派だった(カーテンコールでは最初、傲然と構えていてなんだ? と思ったが、腰が曲がらなくなっていてお辞儀ができないのだった)。数年前は老醜を晒していていやだなと思ったが、ここまで来ると、お呼びがある限り全力を尽くす音楽家として尊敬に値する。

ヨンチョバは期待通りに良いのだが、結局、この声が好きなのだな。

物語はひっくり返るほどあきれ返るもので、領主の息子のロドルフォのあまりの低能っぷり(そもそも偽名を使ってつきあっていて、ヴルムが正体をばらしたら本気でミラー親子が驚いているところも見届けているのだから、ルイザが罠を仕掛けるなんてあり得ないことにふつうは気づくだろう)と腰のひけっぷり(1幕ではよりによってルイザを刺すとか言い出して親父に殺したらいいじゃんと言われてやめる、2幕ではヴルムに拳銃を渡して決闘しようとしてあっという間に逃げられる、3幕では苦い苦いと大騒ぎしてルイザに全然苦くないけどとか鼻であしらわれる)、領主と子分のヴルムの卑劣っぷり、公爵夫人の自己中心っぷりに気分が悪くなる。

が、よくよく考えると、この時代の物語だから、ルイザは14歳でロドルフォは15歳なんだから、まともにものを考えられなくてもしょうがないか。公爵夫人もロドルフォと幼馴染ということは14~5歳だからえらく単純に納得してしまうのも、そう考えれば辻褄はあいまくる。

歌手が歌っているせいで、つい20代の青年たちと思って観てしまうからわけがわからないだけのことだった。

1幕、ロッシーニの混乱シーンでおなじみのポンポコリズムを歌いながら順番に心境を歌う(ヴェルディでこのスタイルを聴くのは今回が初めてだと思う)のが、2幕だと完全に無伴奏でおもしろい。ただロッシーニのせいで、このタイプの歌は喜劇の狂乱の場なのだが、こちらは徹底的な悲劇なので奇妙な感覚を持つ。

2幕はおなじみの曲が流れて(ヴルムがルイザに手紙を書かせるシーン)、ああ、これだったのかと曲想と場面のマッチっぷりにすごく納得した。

2幕のバスの競演は宗教裁判長とフィリポ2世の先取りだな。

3幕のルイザの天国なら自由みたいな歌はベルカントも良いところで、音楽スタイルは無茶苦茶だが、どうもそういう作品(ヴェルディが初期作品の総決算と中期のための助走の実験しまくり)みたいだ(というようなことを幕間インタビューでみんなが語っていておもしろかった)。

幕間のインタビューといえば、1幕後にはヨンチョバが3幕で死んじゃうだけに軽く歌う必要があるとか言い出して、なるほど、これがネタバレというやつかと思った。

ベチャワのインタビューでは、プラシドから何かアドバイスがあったか? というような質問の文脈で、「3幕はオテロで歌えば良い」って言われたけど、そりゃプラシドはオテロも歌うけど、おれは歌ったことないんだよ、と言っていておもしろかった。

ビリーの指揮がとても良かった。序曲の最初の数小節での妙なルバートとそのあとの速度は、導入として見事だった。

というわけで、えらく楽しめた。


2018-05-31

_ rubyでアドホックにxlsxを読む(1:モチベーション)

マスター登録系のWebアプリケーションで、一括登録させたい場合、CSVが比較的利用されていると思う。思う理由は、非プログラマーにとって、デスクトップでの入力アプリケーションといえば、Excelと相場が決まっているからだ。

Excelに入力させた情報をWebにアップロードするなら、ネイティブな形式(xlsかxlsx)が本来は望ましいのだが、ネイティブな形式はバイナリーなので伝統的にCSVが選ばれるのだろう。

CSVは文字列内の,の扱いなどそれなりに厄介なので、タブ区切りのtsvというのが後から出てきたが、後発の悲しさでそれほど主流ではない。というか、よくわからないが、移出形式のファイルといえばcsvというのが不文律みたいだ。

で、これが本格的に厄介になったのは文字コードがからむからだ。

ビジネスの文脈で絵文字が出てくることはそれほどはないかも知れないが、人名地名に広大な文字空間が提供されたので、ふつうにCP932に収まらない文字が入力されまくる。

それをcsvに移出しようとすると、文句が垂れられるのは良いが、押し切ってしまう無頼派(文字化けする)と言われるままにutf-8 CSVというBOM付きCSVを作る順応派の2種類がいて、結局、サーバー側では文字コード判定が必要となる。といっても、先頭3バイト読めば良いので(BOM判定するだけなので)まあ、許容範囲だ。

が、5月のWindows10アップデートから、UTF-8デフォルトという愚かな機能が実装された。まだβ提供なので愚かじゃんという声が大きければ仕様が変わる可能性がないわけでもないが、おそらく突っ走ることになるだろう。

というのは、より良い選択枝がないからだ。

デフォルトUTF-8となると何が起きるかと言うと、コードページがCP932からUTF-8に変わる。

このこと自体は全然望ましいのだが、過去の互換性は最悪となる。

まずメモ帳は、BOM判定はするが、BOMがなければ既定コードページとしてテキストファイルを扱う。つまり、これまで蓄積されたCP932のテキストがメモ帳での読み込みに全滅する。

Excelは過去との互換性は重視するように仕込まれているらしく、BOM無しCSVはすべてCP932として処理する(Excel自体が既定の文字コードを持っているようだ)。

ということは、過去作ったCSV(CP932、読める)、過去作ったBOM付きUTF-8(読める、書ける)、新規に作ったCSV(UTF-8、読めない、書ける)というたすき掛けになる。

これはこれで厄介な状況で、設定変えて、注記なしCSVで保存してもらうと、次はExcelで読めなくなるということだ。

というか、そもそもCSVを選択して出力してくれと依頼した場合に、無印CSVではなくBOM付きUTF-8のCSVが選ばれる可能性があるのだから、厄介事が増えただけのことだった。

というわけで、素直に考えれば、Excelネイティブ形式一択にすれば話が単純となる。文字コードはもともとUTF-8だから考えるまでもない。

あとは、xlsではなくxlsxにしてもらうことだけ気をつければ良い。

というわけで、xlsxが送信されてくることを想定する。

_ rubyでアドホックにxlsxを読む(補足)

ということは、サーバーがCSVを作ってクライアントに対して吐き出す場合は、BOM付きUTF-8が実は最も安全(確実に読んでもらえる)ということになる。

_ rubyでアドホックにxlsxを読む(方法)

xlsxは、zip(pkzip方式)を使った内部にディレクトリ構造を持つ圧縮ファイルで、仕様は[MS-XLSX]: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Formatで公開されている。

ここでは単純にCSVの代替としてxlsxを使うということで、1シート、マトリクス入力のシンプルなxlsxを単に読み取ることを前提とする。書き出しは考えない。

と、決めた瞬間に話がいっきに単純となる。

Rubyでxlsxを扱うには、rooのようなGEMがあるのだが、こいつらはでか過ぎて使う気にまったくなれない。実際のところ、REXMLで十分なので、厄介なのはzipの処理だけだ。

zipは本気で厄介なので、rubyzipを使う。

と決めた時点でXMLパーサとしては、SAX2を使うことが自動で決まる。

xlsxはシートの実体となるxl/worksheets/sheet1.xmlと、文字列の実体となるxl/sharedStrings.xmlの2つのXMLのみ考えれば良い。sheet1.xmlにはすべての1枚目のワークシートの全セルの情報がある。ただし、文字列に関しては、sharedStrings.xml上のインデックスが持たれる。sheet1.xmlという名前から明らかなように、2枚目のワークシートはsheet2.xmlとなる。

読み方は以下の戦略を取る。

zipの全エントリーを列挙し、sheet1.xmlが見つかったら、セルの情報をハッシュに作成する。ハッシュのキーはA1とかAA32といったセル名とする。ハッシュの値はセル内のデータを入れる(当たり前だ)。sheet1.xmlでセルを示す要素名はc、セル名を示す属性はr、型名を示す属性はtだ。c要素に値を示すv要素がネストされる。したがって、SAX2でcを見つけたら、ハッシュにrをキーとして、t属性値とv要素のペアを保持すれば良い。Rubyの場合、タプルの代替としてここでは配列を使う。

zipのエントリーからsharedStrings.xmlを見つけたら、文字列配列を作成する。上でも書いたが、文字列の場合、sheet1.xmlのv要素に入るのは該当配列上の0開始のインデックス番号となる。sharedStrings.xmlは、IME変換情報(カナ入力)や文字修飾情報などが入るので多少厄介だ。基本は1文字列単位にsi要素が作られる。最初に出現するt要素が値としての文字列となる。ただし、文字修飾がある場合、si要素の下に修飾単位に区切ったr要素が作られて、その中の最初のt要素が文字列の実体(部分文字列)となるので、それを拾うことになる。

次のコードは70行で、与えられたパス名またはIO(当然StringIOも可)から、値配列を作る。A1が[0][0]、B1が[0][1]、A2が[1][0]となる。

require 'rexml/parsers/sax2parser'
require 'rexml/sax2listener'
require 'zip'
require 'pp'  # for debugging
def xlsx_to_array_of_array(xlsx)
  dic = []      # 文字列辞書
  table = {}    # シート(セル名をキー、値は[型, 値]
  is = Zip::InputStream.new(xlsx)
  loop do
    ent = is.get_next_entry
    break unless ent          # zipを最後まで読んだ
    if ent.name == 'xl/worksheets/sheet1.xml'
      current = nil           # ハッシュの値用配列入れ
      parser = REXML::Parsers::SAX2Parser.new(ent.get_input_stream.read)
      parser.listen(:start_element, ['c']) {|url, localname, qname, attrs|
        table[attrs['r']] = current = [attrs['t']]
      }
      parser.listen(:characters, ['v']) {|c|
        if current
          current << c
          current = nil
        end
      }
      parser.parse
      pp table if $DEBUG
    elsif ent.name == 'xl/sharedStrings.xml'
      valid = 0       # 本当はFSMを使うほうが良いけど、単純だから状態変数でいいや
      parser = REXML::Parsers::SAX2Parser.new(ent.get_input_stream.read)
      parser.listen(:start_element) {|url, localname, qname, attrs|
        if qname == 'si'  # 文字列エントリーの開始
          valid = 1
        elsif valid == 3  # si内で文字属性を切り替える場合は複数のr内にtが分割される
          #
        elsif valid == 1 && qname == 't' # si直後のtは有効(それ以外はIME変換情報)
          valid = 2
        elsif valid == 1 && qname == 'r' # rを使う場合はr内のすべてのtを利用する
          valid = 3
          dic << ''
        else
          valid = 0
        end
      }
      parser.listen(:characters, ['t']) {|c|
        if valid == 3
          dic.last << c  # si/r/t の場合は分割されているので結合する
        elsif valid == 2
          dic << c       # si/t の場合はエントリー全体を入れる(3の場合の処理を共通で利用しても良いが、バグがあれば上書きされるので後から調べやすい)
        end
      }
      parser.parse
      pp dic if $DEBUG
    end
  end
  csv = []       # 結果の配列の配列用
  table.each do |key, val|
    key =~ /\A([A-Z]+)(\d+)\z/
    col = $1.getbyte(0) - 'A'.getbyte(0)  # 面倒なのでカラムはA~Zまでに収まることにする。AAとかサポートするなら26進数として処理する
    row = $2.to_i - 1
    csv[row] ||= []
    if val[0] == 's'   # 文字列の場合、型はs
      csv[row][col] = dic[val[1].to_i]
    else
      csv[row][col] = val[1]
    end
  end
  pp csv if $DEBUG
  csv
end

2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|

ジェズイットを見習え