今川館

都内勤務の地味OLです

はじめてのwebアプリ② unicode/utf8で文字数を数える

この記事のソースコードこちら

バグを直す

文字数カウントのwebアプリは、以下のバグがあるので直す。

  1. 文字数ではなくバイト数を算出している
  2. HTMLのエスケープをしていない

このため、

<font color="red">𩸽</font>

上記文字列を入力すると、スクリーンショットの通り、fontタグが適用されて文字が赤字表記になり、なおかつ本当は26文字と数えて欲しいにもかかわらず29文字と数えてしまう。

f:id:imagawa_yakata:20161219115328p:plain

文字数ではなくバイト数を算出している

これは前に学んだunicode/utf8のRuneCountInStringで数を調べるよう改める。

[before]

text := r.FormValue("text")
count := len(text)

[after]

// import "unicode/utf8"

text := r.FormValue("text")
count := utf8.RuneCountInString(text)

HTMLのエスケープをかける

次に、HTMLのエスケープをかけるため、html/templateのHTMLEscapeStringを使うことにした。

[before]

content := fmt.Sprintf(`...HTML本文`, text, count, css)

[after]

// import htmlTemplate "html/template"

content := fmt.Sprintf(`...HTML本文`, htmlTemplate.HTMLEscapeString(text), count, css)

text/templateモジュールでHTMLを出力するよう変更

html/templateをよく見たら、HTMLEscapeStringを使わなくても、テンプレート機能を利用すれば出力の式({{.名前}})で自動エスケープしてくれるようだ。

なので、以下の通り改めた。

// import htmlTemplate "html/template"
// import "log"

wc, _ := htmlTemplate.New("wc").Parse(`
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>文字数カウント結果</title>
		<style type="text/css">
			.err { border: solid 1px red; }
		</style>
	</head>

	<body>
		<h1>文字数カウント結果</h1>

		入力文字: {{.text}}<br>
		文字数は: {{.count}}<br>

		でした。<br><br>

		文字を入力してください。
		<form action="/count" method="GET">
		<input type="text" name="text" size="32" class="{{.css}}">
		<input type="submit">
		</form>
	</body>
</html>`)

type Context map[string]interface{}
data := Context{"text": text, "count": count, "css": css}
if err := wc.Execute(w, data); err != nil {
	log.Panic(err)
}

これでHTMLのタグはエスケープされ、文字数も正しく26を数えてくれるようになった。

f:id:imagawa_yakata:20161219115336p:plain