カテゴリー「プログラミング」の12件の記事

2017年7月 9日 (日)

HTMLのaudioオブジェクトで悩む

数字列をメロディにするっていうのを以前に書いたのだが、性能・機能共に満足いかなくてなんとかしたいものだと思っている。

前回書いたものはMIDI.jsという「JavaScriptでMIDIを鳴らす」という仕掛けを使ったのだが、私としては単音のメロディを出せればいいのでいろいろな音色を出せる必要はない。MIDI.jsの基になっているHTMLaudioElementを使えばいいかな、と思った。

で、まずは音源を作ってみた。こんな音だ。とりあえず0.5秒。



T60wav

この音は計算だけで作っているので、予めデータを用意しなくても、音を出す現場でちゃっちゃっと計算して作ることもできる、と思う。音の分解能を落としているので0.5秒の音声データ(WAV)で21.5Kbyte、圧縮してmp3にするとわずか3.32Kbyteになったりする。

で、この音源を、

<audio src=..../T60.mp3 autoplay=true>

というふうにWEBpageに埋め込むと、とりあえず音を鳴らすことができる。ここをクリック

ただし、このaudioオブジェクトというのはまだ発展途上で、すべてのブラウザで動作するわけではない。ブラウザによってサポートしているファイル形式が違っていたりするので、上のリンクをクリックしても音が出るとは限らない。

さらに、このaudioオブジェクトというのは仕様がおかしくて、例えば先のautoplayをfalseにしたら音が鳴らないはずだが、実際には鳴ってしまう。ここをクリック

TrueにしろFalseにしろAutPlayを指定してしまうとページを開いたとたんに鳴ってしまうので、Autoplayの指定はできないことになる。

この仕様がもうちょっと出来が良ければ、出したい音程の数だけaudioオブジェクトを並べて、鳴らしたい音を順次playさせていけばいいと思うのだが、これがなかなかうまく行かないのだ。

音を鳴らしたいタイミングでDocument.writeでaudioオブジェクトを生成するという荒業もできなくはないが、いろんな処理が走るので音が出るまでの時間が不確定だ。すぐに鳴ったり遅れてなったりとかのへたくそな音列になりそうで躊躇している。

以前にも紹介しているが、オブジェクトのプロパティを列挙する仕掛けを作ってあるのだが、このaudioオブジェクトの素性を探ってやろうと思ってこの仕掛けを適用してもうまくいかない。何か特殊なやりかたが必要なんだろうか? と悩み中。

7月17日追記:

audioオブジェクトって、タグで定義するのではなくて、newしてコンストラクタを呼び出して作るものらしい。実際、そうやってみるとAudioオブジェクトのプロパティを表示することができた。また、このオブジェクトを配列として任意の音をJavascriptから発音させることもできた。

らだ、なぜかD3(レ)の音がオクターブ高くなったりする。これはWAVをmp3にするあたりで何か失敗をやらかしているらしい。横着をしてWAVをmp3に一括変換したのがいけなかったのかな?

まぁいろいろと道が開けたので、もっと遊んでみようと思う。

| | コメント (0)

2017年4月 1日 (土)

JavaScriptで悩む

Javascript1999 JavaScriptはブラウザ上で動作するプログラムだ。cgiと違ってサーバと通信しなくてもブラウザ上で利用者の操作に反応して動けるので反応がよく、音楽を扱ったりするのにはいいと思った。

しかし、JavaScriptって仕様がよくわからない。前にも使っていたことがあるのだが、何分にも20世紀の話で、最近では昔の参考書に載っていないような文法があったりする。基本的なところからやり直さないと、こういうのをブラッシュアップすることもできない。
Spacer480x5
で、こんなのを作ってみたりして(WAVEボタンを何度も押してはいけません)。

さらにはこんなのも作ってみた。CGIだとボタンを押すたびにサーバと通信して画面が書き換わるのだが、JavaScriptなのでその場で結果が出る。

しかし、オブジェクト指向のはずなんだが、いちいち気に入らないなぁ。数字と文字で「+」の意味が変わるなんて、昔は受けたかもしれないが、そのために演算対象の属性がはっきりしなくなってString()とかNumber()を使うなんてのは本末転倒なんじゃないの?

で、いろいろなオブジェクトのプロパティを調べようと思ってこんなのを作ってみたのだが、出来としては今一つだなぁ。オブジェクトをクリックするとそのプロパティが表示されるようにしたかったのだが、CGIを使ってしかも手動でオブジェくト名を入力しないとだめという情けないものになってしまった。

しかも、「 for (property in object){...}」という感じでプロパティを表示するのに、プロパティ名でソートしたいのにobjectにはそういうmethodがないときたもんだ。正規表現も言語的には実装されていないし(関数の無理使い)、まだまだperlからは離れられないなぁ。

| | コメント (0)

2016年7月 3日 (日)

プログラム言語「Ruby」で悩む

ちょっとしたプログラムを書くのにはPerlという言語を使っている。エレガントさには欠けるが強力な言語だ。配列を扱うのに強力な機能を持っている。

一方、20世紀末あたりから新しい傾向の言語がいろいろと出てきた。具体的に言うとPythonとRubyだが、Pythonはどうも好きになれないし、実際に使ってみてもメリットを感じなかった。

Rubyはなんだかライブラリが充実している(Ruby Rails)とかで、初心者が安易な気持ちで入門できるのかなぁ? という感じが嫌で食わず嫌いになっていた。

最近になってRubyが気になりだしたのは、その文法や構成がPerlを意識したものであるらしいと思ったからだ。いろいろな機能に「PerlでできることはRubyでも可能にするんだ!」という意思を感じる。それならPerlから乗り換えてもいいんじゃないか、と思った。

ところで、Rubyは「純粋オブジェクト指向言語:Pure Object-Oriented Language」なんだそうで、それってことは組み込みクラスとか組み込みメソドとかの情報をかなり覚えないといけない。

Perlのときは基本的なことを「Programming Perl」で学んだあとはデスクトップ・リファレンスだけを頼りに使ってきた。Rubyの場合は、特に急いでいるわけでもないのでデスクトップ・リファレンスだけでなんとか使えるようになってやろうか、という魂胆だ。

というのは、「Programming Perl」でさんざん苦労したからだ。この本は760ページもある本で、しかも内容には「……というのは冗談として」みたいな無駄話が多く、全部読み切るのに5年かかったのだった。

Perlruby

これらの本を並べてみるとこんなふうになる。プログラミングPerlが760ページ、そのデスクトップ・リファレンスが50ページなのだが、Rubyのデスクトップ・リファレンスはなんと156ページもある。「プログラミングRuby」という本も出ているはずだが、そのページ数は想像するだけでも恐ろしい。

しかし、Rubyのお勉強を始めてみると、これがなかなかの手ごたえで、同じことをperlとrubyで書くとこんなふうになる。どちらもわざわざchompしているのはprintで"\n"を明示したかったから。

<perl>
while(<>){
    chomp;
    print "$_\n";
}
<ruby>
while gets
    chomp
    print "#{$_}\n"
end

Rubyでこんなふう(perlふう)に書くのは可能ではあるけれども、Rubyの設計者(日本人)の意図とは違うようで、本来ならばこんなふうに「ファイルから一行ずつ読み込んで、終わりじゃないことをチェックし」「読み込んだ行を処理する」という構造じゃなくて、ファイルをストリーム・オブジェクトとして定義し、ストリームとして処理することを意図しているんじゃないだろうか。

それは私がPerlからRubyに移行しようかと考える一つの理由で、こういうのはもう古いんじゃないか、もうちょっと新鮮なやり方があるだろうと思うからだ。

いまさらオブジェクト指向が新鮮かというと、それにもちょっと疑問があるのだが、そのあたりを考え直すきっかけにもなったらいいなと思う。

オブジェクト指向については大昔にSmallTalkの仕様をさんざん読んだことがあって、その影響のためにC++の欺瞞性(オブジェクト指向の無理矢理な言い換え)がどうにも許せず、行き所を失っているというのが正直なところなので、Rubyがその回答になってくれればいいな、と思っている。時間はかかるかもしれないけれどもね。


| | コメント (4)

2015年9月 6日 (日)

苗字の漢字で悩む

日本人の苗字について書いてみたりしたら、思いがけないコメントをいただいたりしたので、実際のところ苗字に使われている漢字ってどういうものなんだろう?と検証してみようと思った。

ネット上に日本人の苗字を12万件ほど集めていたところがあったので、それらの苗字を漢字一文字ずつバラバラにしてまず出現数の総計をとってみた。つまりどんな漢字がどれくらい使われているか?ということだが、ここでは田中とか中村とか鈴木という名前を持つ人が多いということとは関係なくて、ひたすら苗字の件数(種類)を数えているので、お間違えのないよう。

集計したものをEXCELにしたので、利用できるなら利用していただきたい。ただしミスがあるかもしれず、そのへんは責任持てないよ~ってことで。

「漢字in苗字.xls」をダウンロード(ただしファイル名は「in.xls」になる)

で、集計してみたところ、まず苗字の長さについてはこういう結果が出た。
一文字苗字 2144件
二文字苗字 99742件
三文字苗字 24081件
四文字苗字 483件
五文字苗字 2件
五文字苗字の2件は
・勘解由小路
・左衛門三郎

ということだが、まぁそいういうこともあるのかな?と。

で、それぞれの漢字が例えば二文字苗字の何文字目に出てくるのかな?ということを知りたいのでそれを計算してみる。データは3000行以上あるので、最初の方だけを紹介する。詳細はEXCELシートをダウンロードして遊んでいただきたい。一文字苗字は意味ないかと思って省略したが、今考えてみると付けても良かったかも。

Jfnames1
案外普段見ないような字が出てくるもんだなぁ、という印象だが、それはそれぞれの苗字を使っている人の人口分布が加味されたものを体験しているからで、ここではあくまでも「山田」であっても「勘解由小路」であっても1件として対等に扱っているからなので。

さて、それでこれをグラフにしてみたらなにか有意なものが出てくるかなぁと思うのだが、これをこのままグラフにするとこんな感じであまり面白くない(最初の300件についてグラフ化した)。

Jfnamesg1
そこで、総計出現回数を100%としてパーセンテージを計算してみた。ただしこの部分はダウンロード用に用意したデータには入っていない。数式をてんこ盛りにするとcocologのupload容量を超えてしまうのだ。

というわけでパーセンテージを計算したものがこの表だ。

Jfnames1p
この表の最初の300件をを二文字苗字の一文字目で降順ソートしグラフ化したのがこれだ。と書いてから思ったが、全体をソートしたほうが良かったかもしれないな。まぁそれは興味をお持ちのあなたにもできることなので。

Jfnamesg2 紺色のグラフが右下がりになっているところへ、ピンクの線(二文字苗字の二文字目)が右上がりになっているのが何やら意味ありげだ。やはり一文字目に来やすい文字と2文字目に来やすい文字があるのだろう。

ならば、と三文字苗字の1文字目で降順ソートしてみる。

Jfnamesg3
黄色と水色と紫色の関係を見たいのだが、むしろピンクのグラフの右上がりが気になるところだ。

ということなんですが、これからなにか有意なことを導けるでしょうか?

| | コメント (6)

2015年8月16日 (日)

擬似乱数の図示化で悩む

これは山手線の路線図ではない。大阪の環状線のほうが近いようにも思うが、そっちでもない。

ではどっちなのかというと、こっちだ。フォン・ノイマンの中間二乗法あるいは平方採中法と呼ばれるものだ。

図中の矢印は矢印根元の数値を二乗してその中間の二桁を取り出したものが矢印の先の数値になることを示している。ただし計算の結果出てきた「0」は「1」で置き換える。

例えば上の方にある49という数字を二乗すると「2401」なので真ん中の2桁を取り出すと「40」だが、0を1で置き換えるので41になる。

こうやって演算を繰り返していくと、最終的には真ん中の円のなかに飲み込まれてしまう。

あるいは右下にあるように24、57という別の銀河でくるくる回ることになる。

Neuman2   
先日の投稿で、この平方採中法が簡単にリミットサイクルに入ってしまうことを示したが、これを何とか図示したいと思うようになった。図示するための計算は案外簡単だったが、実際のこうやって二次元化するのは全くの手仕事で、結構悩みながらやることになった。VISIOでもあるともっと楽に、綺麗に出来たかもしれない。

作図した後に数が前部出揃っているのかチェックするのがまた一苦労だった、結局紙に印刷して1つずつ塗りつぶすという原始的な作業になった。

この図を見て思うのは、人生流転というか、違ったところに生を受けても結局は大きな流れに飲み込まれていくのかなぁ、とか、最終的には繰り返しになっていくあたりがなんとなく音楽に似ていなくもないなぁ、とか、電車の路線図に似ているのは、必ずしも偶然でもないのかもしれないなぁ、とか。

というわけで、なんとなく夏休みの宿題みたいに、最終的には手仕事になってしまったが、形になったことでなんとなく達成感を得たこの夏の思い出。

同日追記:

残念ながら、ループの中身の順番が違っていました。連想配列に依存して順不同だったのをいるのを忘れていました。ループの順番を補正するのは今はちょっとできないので、また後程修正します。

ループの中はこの順番にならないといけないのだった。
84 15 22 48 31 96 21 44 93 64 19 36 29 84

| | コメント (2)

2013年6月 9日 (日)

ボーカロイドを分析して悩む

悩むくらいだったら分析なんてしなければいいのに・・・、てなことを言うアナタ、オタク体質を理解していませんね~。まぁそんなもの理解したってなんの役にもたちませんけれどもね。でも、分析したから悩むのか、はたまた悩むために分析するのか、とか、まぁそんなことはどうでもいいのだ。

とっかかりは、作ってみた「Understand Me」の最初の部分で「ア」系の発音がなんだか不自然だなぁと感じたことだった。特にこの「アンダースタン・ミー」の「ダー」のところの発音がなんだかハスキーすぎるというか、なんだか不自然だなぁ、ここんところがもうちょっとなんとかなれば本当に人間が歌っているように聞こえなくもないのになぁ、と。

Vocaloid3 Editor(以下V3Eと略)では、「Understand」という単語を辞書を引いて「V n d @r s t { n d」というV3Eの内部発音記号に展開する。問題はこの「@r」の部分だ。 マニュアルを見ると、「@r」には特に記述がなくてその代わりに「@」のところには「シュワ(あいまいな母音)」と書いてある(図はマニュアルからの一部引用)。

V3eman4 「シュワ」って何? 日本語ですかそれ? ボーカロイドが手話? シュワルツネガーと何か関係がある? 他の母音記号にはなんにもコメントがなくて「@」にだけ「シュワ」って? などなど突っ込みどころ多数なのだが、結局のところなんだかサッパリ分からない(ガリレオふう)。

で、その周波数スペクトルを取ってみたのが次の図だ。なんだか高域までチャラチャラといろいろ入っているが、-60dB以下は多分聞こえないだろうと思うので無視して、どうも赤く囲んだ部分がうるさく耳に付いているんではないか、という気がする。




R8barspec

実際にこのスペクトル解析を行った音をmp3にしてあるので聞いていただこうか。



だから、この音声ファイルから3khz以上をバッサリを切り落とせるようなチェビシェフ・フィルタみたいなのがWindowsのアプリケーションとしてないものかと探してみたのだが、意外とないもので、Mathmaticaとかなんだかそういう数学ライブラリには入っていたりするんだろうか? SourceForgeを探してみたが、やはりそういうプロジェクトもないようだし。
Windows上でWaveファイルを処理できるデジタルフィルタって、意外と便利なんじゃないかと思うんだが、誰か作ってくれないかな。

しかたがないので、昔学校で習ったZ変換とかで何とかやってみようと思ったのだが、WEBにあるZ変換のサイトを見てもこれまたさっぱりわからない。これは原義に立ち返ってちまちまとプログラムを書くしかないんだろうか? perlで書いてみたらファイルの入出力だけで30分かかったりして非常に遅い。メモリの利用効率が悪いので、こういう多量データの計算には向いてないんだろうなぁ。Cで書くか?それもめんどくさいなぁ。

仮計算をしてみると、そもそも16bitPCMオーディオというのが計算には全然向いていないっていうか、デジタルフィルタ的計算をやろうとすると計算精度が全然足りない。確かに16bit44.1kサンプル/秒というのはオーディを記録するにはいいんだろうけど計算するにはその倍以上の精度が必要なようだ。これは結構めんどくさいぞ。

というわけなので、Z変換をはじめとするデジタルフィルタなんかを再履修中。

翌日追記:
恥ずかしながら今まで知らなかったのだが、シュワっていうのはこれのことだったらしい。
Schuwa
この発音記号のことをシュワ(Schwa)っていうのかっ!? 何語だよっ?!

この発音記号はよく知っているが、「あいまいなア~」とは知らなかった。

これはさりげなく発音できると英語がうまく聞こえるらしいぞ。

(つづく)

| | コメント (1)

2012年8月24日 (金)

数独の問題作りに悩む

Sudokufail数独の問題を解くプログラムはそれほど難しくなかったが、問題を作るのはむつかしそうだ。

数独の問題を作るのに、端から順番にルールに合致できる数字を乱数で選びながら埋めて行ったりしてみたのだが、そうやってみるとおしまいの方になってつじつまを合わせられなくなり、ルールに合う数字を入れられなくなる、という事態になってしまう。

左に掲げたのがその例で、左上から順番に数値を決めていくのだが、途中でルールに合う数字を見つけられなくなる。例では「#」で表されているのがその状況で、右下へ行くに従って苦しくなってきているのが分かると思う。

まぁ力技としては、そんな方法であってもルールに合った(以降、「正則である」ということにする)組み合わせだけを取り出すこともできるが、どれだけ時間がかかるかわからないし、全ての正則な組み合わせを網羅できるかどうかもわからない。試しにやってみたら10000回の試行で30個ほどしか満足な問題が作れないので、そんなのやってられないな、と。

なので、ある正則な組み合わせを変形させていくことを考える。例えば正則な組み合わせの縦の列を別の列と入れ替えると、縦と横のルールは保つことができる。でもそれだと3×3のボックスのルールを保つことができない。

Sudokugenなので、この図に示すように例えば上段の3つの3×3ボックス間で縦3個の数字を他のボックスの同じ位置にある縦3個と入れ替える。図中では赤、緑、青で示した3個ずつの数字を同じ色同士で入れ替えることになる。

赤で示された3つの3数字を並べ替える組み合わせは6通りなので、上段で三色のそれぞれを入れ替える組み合わせは216通りになる。中段でも下段でも同様に216通りのバリエーションを作ることができ、このように短い縦の列の入れ替えで216の3乗:10,077,696通りの組み合わせを作ることができる。

さらに同様の操作を短い横の行に対しても行うことができるので、組み合わせは更に大きくなって、216の6乗:101,559,956,668,416通りになるが、とりあえず割り当ててある1~9の数字の割り当ては自由に変えられる(例えば4を2に、2を4にとか)ので、9の階乗:362,880をさらに掛けないといけない。すると36,854,077,075,834,798,080
とかいう、なんと読んでいいのやらわからない数字になってしまう。

ただし、問題の盤面を回転させたり、裏返したりしたものを同じと数えないという事にすると、8で割って4,606,759,634,479,349,760ということになる。

一方Wikiでは9×9の数独に関して約54億通りという計算結果が出ているのだそうで(コンピュータで数え上げたらしい)、上記の値とは大きな隔たりがある。数字を3つずつ入れ替えるだけで全てのパターンを生成できるのかどうか、今ひとつ確信が持てないが、まぁそんなもんじゃないかな。

だいたい考えて見ると、数字の配列というのは問題の難易度にそれほど関係してこないと思うのだ。問題の難易度というのは、問題を解き始める時点で自明な解がどれくらい露出しているか、ということが問題になるのだろう。

自明な解というのは、数独を解くプログラムの時に示した、赤く表示されるパターンのことを言っている。例に引いたDELTAでもらった問題では、最初に私が取り付いたマスが自明な解を持っていなかったのだったが、問題を見てぱっと自明解を見つけることが出来れば、その問題はとっつきやすい問題ということになるだろう。

問題の面白さ、ということを考えるとするならば、問題を解き進むに連れて自明解の数がどんなふうに変化するか、ということが大きなファクターになってくるのだと思う。

Sudokuans

ここで、左端のパターンは最初から自明解がたくさん露出していて、解き進むに従って自明解が減っていくというもの。とっつきやすいから初心者向けといえるのではないだろうか。

真ん中のパターンは最初の自明解が少なく、解き進むに従って自明解がどんどん増えていくという、上級者向けのパターン。右端は上級者向けと同じように解き進むについて自明解が増えてくるが、また減ってきてもう一度頭をひねることになる、というパターン。

だから、数字の並びは正則でありさえすればどうでもいいので、その数字たちのどの部分を隠すか、というのが考えどころ、ということなんだと思う。じゃぁそれをどうすればいいのか?というのは、まだ考え中。

翌日追記:

一般に流布されている問題を解かせてみたら、一般の問題ってのは「自明な解」のマスが最初から無い、というのが多いようで。私がたまたま入手したDELTAの数独が特別に簡単なもんだったということなのか。そりゃ解くプログラムも簡単なはずだわ。

自明な解が予め存在しないような問題だと、脈のありそうなマスの関連性をたどって試行錯誤しないといけない。それならよくあるゲーム解法のプログラミングになってしまうんだろうなぁ。それはなんだかあんまり面白くないなぁ。

| | コメント (2)

2011年9月25日 (日)

Perlの二次元配列で悩む

Perlの機能を確認するには、デバッグモードで起動すると便利だ。LinuxでもWindowsでもコマンドラインから-de0というオプションをつけるとデバッグモードになる。

D:\WORK>perl -de0 Loading DB routines from perl5db.pl version 1.31 Editor support available. Enter h or `h h' for help, or `perldoc perldebug' for more help. main::(-e:1): 0

まず普通の1次元配列を作る。


DB<1> @x=qw(abc def ghi jkl)

Xコマンドで配列の中身を表示させると、当然こうなっている。


DB<2> X x
@x = (
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
)

作った一次元配列@xを@yにコピーする。


DB<3> @y=@x

その中身は当然同じである。


DB<4> X y
@y = (
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
)

コピーした@yの2番目(ゼロから数えて)の要素を書き換える。


DB<5> $y[2]="###"

@xと@yを比べると、@yは変更されているが、当然@xは変更されていない。そりゃあたりまえだ。


DB<6> X x y
@y = (
0 'abc'
1 'def'
2 '###'
3 'jkl'
)
@x = (
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
)

では、これが二次元配列になるとどうか?

同じように二次元配列@xを作って@yにコピーし、@yの要素を変更してみる。

DB<7> @x=([qw(abc def ghi jkl mn)],[qw(opq rst uvw xyz)])
DB<8> X x
@x = (
0 ARRAY(0x1d54ee0) 0 'abc' 1 'def' 2 'ghi' 3 'jkl' 4 'mn' 1 ARRAY(0x1d3ab90) 0 'opq' 1 'rst' 2 'uvw' 3 'xyz' )

DB<9> @y=@x

DB<10> X y
@y = (
0 ARRAY(0x1d54ee0)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d3ab90)
0 'opq'
1 'rst'
2 'uvw'
3 'xyz'
)
DB<11> $y[1][3]="###"

DB<12> X y
@y = (
0 ARRAY(0x1d54ee0)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d3ab90)
0 'opq'
1 'rst'
2 'uvw'
3 '###'
)

すると、@xも変わってしまっているではないか!?


DB<13> X x
@x = (
0 ARRAY(0x1d54ee0)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d3ab90)
0 'opq'
1 'rst'
2 'uvw'
3 '###'
)

なんとこれはPerlの仕様なのである。Perlの多次元配列は「参照」で実装されているので、コピーしたつもりになっていても実際には「参照のコピー」なので実体は同じものをさしており、コピーしたものを変更するとオリジナルも変更されてしまう。これは困った。

ループを回して新しい配列に代入すればもちろん実体コピーができるのだが、できればそんなことはしたくない。なにかうまい手は無いか?

二次元配列の一つ一つについてコピーすればいいのだから、map関数が使えそうな気がする。
これでどうだろう?


DB<14> @y=map @{$_},@x

DB<15> X y
@y = (
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
5 'opq'
6 'rst'
7 'uvw'
8 '###'
)

ありゃりゃ、配列が一次元になってしまった。しかし方向性としては間違っていないみたいだぞ。
これでどうだ?


DB<16> @y=map @{$_},\@x

DB<17> X y
@y = (
0 ARRAY(0x1d54ee0)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d3ab90)
0 'opq'
1 'rst'
2 'uvw'
3 '###'
)

これは一見うまくいったように見えるが、表示されているアドレスを見ると@xと同じで、つまりやはり参照がコピーされていることが分かる。これだとやはりコピーを変更するとオリジナルも変わってしまう。

map関数の中で配列になるよう[]でくくってみよう。


DB<18> @y=map [@{$_}],\@x

DB<19> X y
@y = (
0 ARRAY(0x1d5b370)
0 ARRAY(0x1d54ee0)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d3ab90)
0 'opq'
1 'rst'
2 'uvw'
3 '###'
)

うむぅ、配列の次元がひとつ上がってしまった。これはまずい。オリジナルを参照しているからいけないのか?


DB<20> @y=map [@{$_}],@x

DB<21> X y
@y = (
0 ARRAY(0x1d5b364)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d5b2c8)
0 'opq'
1 'rst'
2 'uvw'
3 '###'
)

おお、これは行けそうな気がする。コピーの要素を変更してみよう。


DB<22> $y[1][3]="!!!"

さぁどうだっ!?


DB<23> X x y
@y = (
0 ARRAY(0x1d5b364)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d5b2c8)
0 'opq'
1 'rst'
2 'uvw'
3 '!!!'
)
@x = (
0 ARRAY(0x1d54ee0)
0 'abc'
1 'def'
2 'ghi'
3 'jkl'
4 'mn'
1 ARRAY(0x1d3ab90)
0 'opq'
1 'rst'
2 'uvw'
3 '###'
)

よしよし、これでいいみたいだな。

| | コメント (0) | トラックバック (0)

2011年3月 7日 (月)

Perl 5.12で悩む

Perlの最新Windows版5.12をインストールしたら「Release Noteを読むか?」というので、ちょっと気になって読んでみたら、「今までのバージョンをインストールしていたら、綺麗に取り除くこと」とか書いてあって、なんだ?PERLのフォルダを削除すればいいのかな? と思ったら、環境変数を削除しろとかはてはレジストリの項目を削除するとかいろいろ書いてあった。

しかし、これが表示されるのはインストールが終了してからなので、この時にはまっ更なPCにインストールしたから良かったようなものの、自宅のPCにインストールするのはちょっとためらってしまう。

と思ったら、Release Noteをインストール前に読むことができるのであった。

Known Issues > Windows

「ActivePerl MSI installerでトラブっている人がいるらしいけど、このバージョンは古いバージョンのperlに対して絶対に上書きインストールしちゃいけないよ。」などと書いてあって、「まずインストーラを止めよ。」

c:\> net stop "Windows Installer"

で、「PERLLIB と PERL5LIBの環境変数を削除せよ」、そして「以下のレジストリを削除するかRenameせよ」ということだ。

[\\HKEY_LOCAL_MACHINE\Software\Perl] lib = (REG_SV)
[\\HKEY_LOCAL_MACHINE\Software\Perl] sitelib = (REG_SV)
[\\HKEY_LOCAL_MACHINE\Software\Perl] lib- = (REG_SV)
[\\HKEY_LOCAL_MACHINE\Software\Perl] sitelib- = (REG_SV)

こんなこと普通やらないよなぁ。これでハマっている人は結構いるんじゃないかと思うぞ。


| | コメント (0) | トラックバック (0)

2010年9月 9日 (木)

perlのパターンマッチングで悩む

perlのパターンマッチングがおかしな動きをする。これはバグなんじゃないかと思うんだが、Known Issueにも上がっていないようだしなぁ。

どういう話かというと、perlの正規表現でパターンマッチング検索を行ってそのヒット結果を$1とか$2とかの特殊変数でアクセスできるのだが、ヒットしなかった場合にも前回のヒット結果が残ってしまっている、という。

DB<1> $s='13:46 1:46pm 01:46pm pm1:46'
DB<2> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1
01:46pm

上記では「13:46 1:46pm 01:46pm pm1:46」という文字列から「[012][0-9]:[0-5][0-9][ap]m」というパターンを探してもらいたい、ということを試行している。この要求は厳密で、24時制ではなくて後ろにamまたはpmを付けた12時制で、1時ではなく01時と表記したものだけを拾うということを意図している。カギ括弧でくくられた文字はその位置にそれらの文字だけが許されることを示している。この試行は成功している。

ところが、この直後にパターンマッチングに失敗する例を持ってくるとどうなるか。

DB<3> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;$s=~/(abc)/;print $1 01:46pm01:46pm

同じ文字列の中から「abc」を探せという2回目のパターンマッチングには失敗しているのに、あたかも成功したかのように$1には前回のマッチング結果が残っているので、01:46pmというのが2回表示されてしまう。

これを回避するにはパターンマッチングに成功したかどうかを毎回調べないといけない。

DB<4> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;if ($s=~/(abc)/) {print $1;} 01:46pm

こうやれば確かにうまく行くのだが、これはめんどくさいし、こんなふうに出来ないこともある。2回目のマッチングを行う前に$1をクリアできればいいのだが、

DB<5> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;$1='';$s=~/(abc)/;print $1 01:46pmModification of a read-only value attempted at (eval 23)[C:/Perl/lib/perl 5db.pl:638] line 2.

特殊変数$1はreadOnlyだから変更できないよ、と怒られてしまう。

ふむ、じゃぁ成功するけれどもnulを返すマッチングをやらせればいいのかな?

DB<6> $s=~/([012][0-9]:[0-5][0-9]pm)/;print $1;$s=~/()/;$s=~/(abc)/;print $1 01:46pm

うん、これでうまく行くみたいだな。

| | コメント (1) | トラックバック (0)

より以前の記事一覧