2015/04/28

[ブロガー向け]文章スタイルプレビュー ver2.0

昨日公開したver1.0だが、Twitterで早速指摘を頂いた。

→XSSの脅威もあるので、<や>などをエスケープすることで対応(ver1.1)

そしてこの指摘。ごもっともである。一応言い訳をすると、段落ごとの入力を想定していて、本来しっかりとした文章ならば段落内での改行はまずないわけで…
とは言っても、ブログとレポートや論文は違うし、むしろどこで改行を入れれば見やすくなるか、というのもまた重大な問題であるから、これに対応しようじゃないか、というのが今回のver2.0である。

昨日の段階で、textareaにCSSを適用できることを発見した。故にこの仕様を使って改変することにした。

ver1.1では入力欄の文字列を取得し、1文字ずつエスケープが必要かどうかを判定し新たな文字列を作成。その文字列を結果表示欄に挿入し、結果表示欄にCSSを適用していた。
一方ver2.0では入力欄のtextareaそのものにCSSを適用することで、処理が大幅に減った上に、textareaであるためHTMLタグなどのエスケープも必要無くなり、コードも大幅にシンプルになっている。

文章スタイルプレビュー ver2.0 ソースコードは以下。


2015/04/27

[ブロガー向け]文章スタイルプレビュー ver1.0公開

ブログのデザインに関して色々試行錯誤している。デザインと言っても、色がどうとか、シャレオツさがどうとかなどは全く興味が無い。問題は、記事表示欄の横幅と、フォントサイズと、そして行間なのだ。
これらの要素は記事の読みやすさに直結する。だが、一々CSSの該当する場所をいじるのが面倒で面倒でしかたがない。そこで作ったのが文章スタイルプレビューだ。

表示領域の横幅、文字サイズ、行間の値を入力すると、それらをCSSに適応した場合の表示がどうなるのかを簡単に調べることができるようにしている。
ver1.0段階では上記3つの要素についてのみ扱っているが、今後他の要素(まあ、無いとは思うが文字の色指定したいとか)をも考慮に入れたくなったら、追加することは十分可能である。私自身使っているうちに必要に応じて追加するつもりだが、「この要素を扱えるようにしろ」という意見があればコメント欄またはTwitterで連絡をいただければ、追加したいと思っている。

2015/04/25

[javascript]複数の関数で扱う変数の宣言

艦これ・制空値計算スクリプトの制作の最後の最後で引っかかったのが表題の通り、複数の関数に渡って使用される変数をどうすればいいのかという問題だった。
具体的には以下の部分だ。

function loadsubmit(shipnum,lnum1,lnum2,lnum3,lnum4){
 switch(parseInt(shipnum)){
  case 1:
   loadArray1[0] = lnum1;
   loadArray1[1] = lnum2;
   loadArray1[2] = lnum3;
   loadArray1[3] = lnum4;
   break;
  case 2:
   loadArray2[0] = lnum1;
   loadArray2[1] = lnum2;
   loadArray2[2] = lnum3;
   loadArray2[3] = lnum4;
   break;
  case 3:
   loadArray3[0] = lnum1;
   loadArray3[1] = lnum2;
   loadArray3[2] = lnum3;
   loadArray3[3] = lnum4;
   break;
  case 4:
   loadArray4[0] = lnum1;
   loadArray4[1] = lnum2;
   loadArray4[2] = lnum3;
   loadArray4[3] = lnum4;
   break;
  case 5:
   loadArray5[0] = lnum1;
   loadArray5[1] = lnum2;
   loadArray5[2] = lnum3;
   loadArray5[3] = lnum4;
   break;
  case 6:
   loadArray6[0] = lnum1;
   loadArray6[1] = lnum2;
   loadArray6[2] = lnum3;
   loadArray6[3] = lnum4;
   break;
  default:
   break;
 }
}
function submitAircraft(shipnum,slonum,toair){
 switch(parseInt(shipnum)){
  case 1:
   toAir1[slonum-1] = toair;
   break;
  case 2:
   toAir2[slonum-1] = toair;
   break;
  case 3:
   toAir3[slonum-1] = toair;
   break;
  case 4:
   toAir4[slonum-1] = toair;
   break;
  case 5:
   toAir5[slonum-1] = toair;
   break;
  case 6:
   toAir6[slonum-1] = toair;
   break;
  default:
   break;
 }
}
function calc(){
 var result = 0;
 for(i=0; i<4; i++){
  result += Math.floor(Math.sqrt(loadArray1[i])*toAir1[i]);
  result += Math.floor(Math.sqrt(loadArray2[i])*toAir2[i]);
  result += Math.floor(Math.sqrt(loadArray3[i])*toAir3[i]);
  result += Math.floor(Math.sqrt(loadArray4[i])*toAir4[i]);
  result += Math.floor(Math.sqrt(loadArray5[i])*toAir5[i]);
  result += Math.floor(Math.sqrt(loadArray6[i])*toAir6[i]);
 }
 var ele = document.getElementById('result');
 ele.innerHTML = '対空値は'+result+'っぽい';
}

対空値は艦載機の積載数の平方根とその艦載機の対空値の積によって求めることができる。よって艦載機の積載数の行列loadArraykと艦載機の対空値を代入した行列toAirkを6隻分用意し(ともにkは艦の番号。1≦k≦6)、calc関数でそれらふたつの行列のi個目(0≦i≦3)同士を掛けて足しあわせていくことにした。
その際、当初は艦名を選択した際に実行されるsetShipname関数から、艦の番号(何隻目か、ということ)とその積載数(最大4スロット)を引数として呼び出されるloadsubmit関数内でloadArraykを、艦載機を選択した際に実行されるsetAircraft関数から、艦の番号、スロットの番号、対空値を引数として呼び出されるloadaircraft関数内でtoAirkを宣言し、代入していた。
しかしそれではcalc変数からそれら2つの行列を呼び出しても、読み込むことができなかったのだ。

そこで色々と調べた結果、変数のスコープ (JavaScript)に行き着いた。これによればjavascriptにおいてはプログラム内のどこからでも、即ち複数の別の関数から扱えるグローバル変数と、関数内で宣言し、その関数でしか扱えないローカル変数がある、ということらしい。
 つまり、先ほどの宣言の仕方では、loadArrayはloadsubmit関数、toAirはloadairctaft関数でしか扱えなくなっている、ということだ。2つとも関数内で宣言しているため、ローカル変数となっているからだ。
 その対処として、これら2つの行列をグローバル変数として宣言する必要がある。つまり、関数の外で宣言すればいいということになる。

//グローバル変数宣言
var loadArray1 = [0,0,0,0];
var loadArray2 = [0,0,0,0];
var loadArray3 = [0,0,0,0];
var loadArray4 = [0,0,0,0];
var loadArray5 = [0,0,0,0];
var loadArray6 = [0,0,0,0];
var toAir1 = [0,0,0,0];
var toAir2 = [0,0,0,0];
var toAir3 = [0,0,0,0];
var toAir4 = [0,0,0,0];
var toAir5 = [0,0,0,0];
var toAir6 = [0,0,0,0];
(後略)

上述のリンク先によれば、関数内で宣言する場合にも「var」をつけずに宣言すればグローバル変数として扱われるとの記述もあったが、プログラムの冒頭でまとめて宣言しておいたほうが、どの変数はすべての関数で扱えるのか後でわかりやすいかと思い、最初にまとめて宣言することにした。
javascriptはJavaを勉強した時とは違い、実際にスクリプトを作りつつ勉強しているのでそもそも「スコープ」という言葉を知らず、上記のリンク先に行き着くにも少し時間がかかった。
最初は一瞬、面倒な仕様だと思ったが、ローカル変数として宣言した変数は同じ名前で違う関数のローカル変数として宣言することができ、変数名に規則性を持たせることができるため、なかなか使いやすい。(このプログラムでは「selected」というローカル変数がいくつかの関数で使われている。)

まとめ

  • Javascriptの変数は、変数を扱える範囲の違いによってグローバル変数とローカル変数に分けられる。
  • 変数外で宣言するか、varをつけず宣言するグローバル変数はプログラム内どこからでも扱える。
  • 変数内で宣言するローカル変数は宣言した関数内でしか扱えない。
  • 複数の関数で扱う変数は、グローバル変数として宣言しなければならない。

2015/04/21

基本情報技術者試験を受験してきた。

一昨日(19日)、基本情報技術者試験を受けてきた。
自己採点した感じ、マークミスなければ合格してるんじゃないか、という手応えがある(フラグ)。

私は所謂文系の人間で(そもそも文系理系の区分は存在するのかという議論はここではなかったことにする。)、Googleで「基本情報技術者試験 文系」と検索すると色々エピソードがあったり、はたまた「文系でも合格できますか?」みたいな質問があったり(そんなもん人によるとしか言いようがないのだが)、文系のよる受験の情報への需要は存在するのかなあ、と思う。
合格発表は来月だが、もし合格していたら、私自身どう勉強したのか、ということについて少し書きたいなあ、と思っている。
逆にもし落ちていたら、何もなかったことにしよう。来月18日?くらいに発表だったと思うので、それを過ぎても音沙汰なければお察し、ということで。

2015/04/11

ドア、挟みし向こう側。

ここにいう「挟む」とは「指をドアに挟んだよいってええええええええ」とかではなく、「テーブルを挟んで座る。」のような意味合いでの「挟む」である。
などと注釈をつけている時点でこのタイトルは失敗だったのだなあ、とこの時点で思うのだ。

 さて、新学期も始まりこのブログも順調に更新が滞っている。どっちかというと新学期というよりは新アニメのせいで忙しさが増しているのだが、どうせ数ヶ月すれば夏休みだ。
新学期といえば、進学やら就職で新たな住処に移った人もいるだろう。私も2年前のちょうど今頃、本州に入るにはパスポートが必要などと言われる北海道から神奈川へ移り住んだのだった。

新たな住居に移るにあたりよく言われたことが、「新聞の勧誘とかめちゃくちゃたくさん来るよ!」という忠告だった。
まあ確かに、やれ洗剤だの何だのの粗品を釣餌に新聞の契約を求める勧誘があるらしいとは知っていた。だから私もどんな断り方をしようかと、持ち前の性格の悪さでウッキウキだった。
そしてあとはみんな大好きNHKだ。受信を主目的とする機器がウンタラカンタラ、色々と謳ってワンセグ機能付きケータイまで契約必須にすることでお馴染みのNHKだ。終いにはネット契約していたら契約必須にしたいらしいとの噂まである。
そんな彼らがやってくるかもしれない、そう覚悟していた。

 蓋をあけると上述二種の訪問者のうち、やってきたのはNHKだけだった。
Amazonで頼んだゲームソフトが届く予定の日、ついに鳴ったピンポンにウッキウキでドアを開けるとそこにいたのは某放送局の某さんであった。
どうしてこうも人をイライラさせる登場の仕方ができるのだろう、狙っていたとしか思えない。彼は部屋を覗き込み(1Kだから中まで見えてしまう)、ノートパソコンを指し「あれテレビですよね?」などと寝言としても程度の低い戯言をのたまったわけだが、いつから彼の世界ではテレビにキーボードが一体となった製品があったのだろう。
とにかく、それ以来NHKは来ていない。

新聞屋は音沙汰がない。よく考えると近くに新聞屋があるのかもわからない。一応朝早くに新聞配達しているのは見たことがあるから、どこかにはあるのだろうと思う。
ただし私の家に来たことはない。別に来てほしいとも思わない。大学の図書館で読めるからだ。

一方思わぬ伏兵として、しょっちゅう訪れる厄介者がいる。それはインターネットプロバイダの代理店だ。あまりにしょっちゅう訪れていい加減腹が立ってきたのでその手法をワールドワイドに晒すことにした。それがこの記事だ。
彼らはまず早口で名乗る。私も大概早口だが、それよりも早い。なんせ早口に慣れている私が聞き取れない速度で名乗る。
そして「どちら様ですか」と再度の名乗り口上を求めると聞こえないふりをして黙るのである。なるほど、難聴系勧誘員というのが最近のトレンドのようだが、現実にやられてもこちらからドアを蹴破りたいほどのストレッサーにしかならない。或いは勧誘員にすら無視されているのかもしれない。悲しい世界だ。
そんな無視にもへこたれず「どちら様ですか」と数回、壊れたラジオのように問いかけると、観念したのか再度名乗り始める。なんだ聞こえているじゃないか、許すまじ。
名乗り始めたかと思えば再度はっきりしない。どうやらNTTの代理店だか、そんなことを言っているようだ。そして「この地域のインターネットの回線の設備が更新されまして」「通信状況の確認に」などと言い始める。だがこれに騙されてはいけない。まともな更新なら更新前にお知らせするだろう。通信状況に影響するやもしれない設備更新を勝手にするはずもないのだ。
…などと偉そうなことを言っているが一度うっかりドアを開けたことがある実体験から、この時点でもうプロバイダ乗り換えの勧誘はほぼ確定。「忙しいので」とシャットアウトして問題ない。話を聞き続けてもプロバイダ乗り換えの方へ話がゆっくりと、打ち寄せては返す波のように進んでいくだけだ。
中にはしつこいのもいて、「他の方にも忙しい中対応していただいています。」などと食い下がってきたりする。嘘をつけ、他の方にも同じように足蹴にされて若干涙目なのはバレバレだぞ。
或いはその「他の方」は、小学生がいう「みんなあれを買ってもらっている」みたいな正体不明の「みんな」なのかもしれない。
それでも放置しているとピンポン連打、ドアコンコン連打、なんだこいつは。指先についたアロンアルファも真っ青のしつこさだぞ。数分間不愉快なドア越しの圧迫を続けると、彼は諦めたのか去っていった。

結論から言ってしまえば、荷物が届く予定がある時以外は居留守するのが正解だ。
ただやっかいなことに、上のNHKのときや粘着質の彼のように、Amazonから荷物が届く予定の日に限って勧誘が来たりするのである。毎度再配達してもらうわけにもいかぬし、こればかりはどうしようもない。
そのやるせなさに憤って、この記事を書いた。

2015/04/04

[Python]続・指定した文字列でフォルダを作成し、指定したURLのファイルをダウンロードし保存する。

 [Python]指定した文字列でフォルダを作成し、指定したURLのファイルをダウンロードし保存する。の最後で「使っていていくつか問題も見つけたので、自分で使う分には不都合ないが、今後修正することも考えたい。」と書いた。
その「問題」を列挙すると、

  • フォルダを作成しようとする際、既に同名フォルダがあるとエラーとなって処理を中止する。
  • フォルダを作成しようとする際、特定の文字が含まれていると「\uff5e」云々のエラーなど、文字コード関連でエラーが出ることがある。
  • そして上述2つのエラーが両方共exceptで拾われる場合があり、どちらのエラーかすぐにはわからない。

列挙する、と言いつつ実質2つしか見つけていないじゃないか!という感じだが、とりあえずこの2点について修正することにした。

 一点目の修正は簡単だ。取得したページタイトルをフォルダ名とするフォルダがあるかを確かめ、あればそのフォルダへ移動し、なければフォルダを作成するようにすればよい。
ということでこうする。

#画像保存フォルダ作成
title = title.encode('cp932')
checkedpath = os.path.join(os.getcwd(), title)
if(os.path.isdir(checkedpath)):
    print u"同名フォルダが既に存在します。"
    print u"該当フォルダにファイルを保存します。同名ファイルがある場合は上書きします。"
    os.chdir(title)
else:
    try:
        os.mkdir(title)
        os.chdir(title)
        print u"フォルダを作成しました。"
    except:
        print u"フォルダを作成できませんでした。ページタイトルを確認して下さい。"
        print u"処理を中止します。"
        sys.exit()

まずは作成しようとするフォルダのパスを os.path.join(os.getcwd(), title)で作成し、checkpathに代入。

if(os.path.isdir(checkedpath))でそのフォルダが存在するかを確認し、あればフォルダへ移動、なければ前回作った部分の処理を実行するようにした。

 これで1つ目の問題、そして3つ目の問題は解消した。この時点でエラーで終了するのは2つ目の問題、文字コード絡みの場合のみといってもいい。
文字コード絡みのエラーは二種類あるようで、ひとつはタイトルにフォルダ名として使えない文字が含まれている場合、そしてもう一つがshift_jisにエンコードできない場合のようだ。
上述の「\uff5e」云々のエラーは後者の場合のメッセージのようだ。
前者はtitleを1文字ずつチェックし、if文なりswitchなりでフォルダ名に使える文字に変換すればよさそうだ、と解決策を考えたところでとりあえず納得した。
問題は後者で、文字コード関連は未だによくわかっていないのでどうすればいいかわからなかった。

素直に「Python \uff5e」で検索すると、こちらのサイトを発見。

というわけで、
title = title.encode('shift_jis')

title = title.encode('cp932')
に代えてみたところ、このエラーを見ることはとりあえずなくなった。

# coding:utf-8
# Project_KAGA

import urllib2
import re
import os
import urllib
import sys

#対象URL入力
url = raw_input(u"URLを入力してください。--->".encode("shift_jis"))

#URLを開き、ソースを読む。
fp = urllib2.urlopen(url)
html = fp.read()
fp.close()

#画像URL格納リスト作成
rowImglist = []
imglist = []

#画像URL検索
img = re.compile("[正規表現]")
i = 0
while i >= 0:
    m = img.search(html, i)
    if m:
        rowImglist.append(html[m.start():m.end()])
        i = m.start()+1
    else:
        break
#重複削除
for i in rowImglist:
    if not i in imglist:
        imglist.append(i)

#記事タイトル取得
titlestart = re.compile("")
titleend = re.compile("")

ts = titlestart.search(html, 0)
te = titleend.search(html,ts.end())

title = html[ts.end() : te.start()]

#タイトル・画像URL出力
print title.decode('utf_8')
for imgurl in imglist:
    print imgurl

#画像保存フォルダ作成
title = title.encode('cp932')
checkedpath = os.path.join(os.getcwd(), title)
if(os.path.isdir(checkedpath)):
    print u"同名フォルダが既に存在します。"
    print u"該当フォルダにファイルを保存します。同名ファイルがある場合は上書きします。"
    os.chdir(title)
else:
    try:
        os.mkdir(title)
        os.chdir(title)
        print u"フォルダを作成しました。"
    except:
        print u"フォルダを作成できませんでした。ページタイトルを確認して下さい。"
        print u"処理を中止します。"
        sys.exit()

#画像ダウンロード
i = 1
for imgurl in imglist:
    savepath = os.path.join(os.getcwd(), os.path.basename(imgurl))
    urllib.urlretrieve(imgurl, savepath)
    print str(i)+u"枚目ダウンロード完了"
    i+=1
print u'ダウンロードが完了しました。'

とりあえずこんな形に。
現状「フォルダを作成できませんでした。ページタイトルを確認して下さい。」というメッセージが出たらまずフォルダ名に使えない文字がページタイトルにある場合だが、このメッセージが出ること自体滅多にないので、とりあえずそちらは放置で。
あとは正規表現を対象のサイトに合わせてどう書くか、というのが問題かな、と。
こればっかりは正規表現に色々触れて慣れるしかないと思った。