Java – 配列 – 初期化

イニシャライザーによる初期化

全要素が同じ型の配列をイニシャライザーで初期化する書き方。typeはプリミティブ型でも参照型でもよい。

type[] arrayName = {emelent1, emenent2, ...};

newによる初期化

newによる配列インスタンスの生成の書き方。typeはプリミティブ型でも参照型でもよい。

type[] arrayName = new type[length];

以下の例では、配列を生成した後に一つずつ要素を定義している。

newによる初期化直後の値はプリミティブ型ならそれぞれのデフォルト値、参照型ならnullになる。

newによる初期化とイニシャライザー

配列宣言時ではなく、宣言済みの配列変数をイニシャライザーで初期化する書き方。

単にイニシャライザーで代入しようとするとエラーになるので、newによる配列の生成とイニシャライザーによる定義を同時に行う。

1つ目のint[]に関してはイニシャライザーによる初期化と同じだが、2つ目のString[]のように一度宣言された変数に対して新たな配列で初期化する場合に有効。

 

Java – プリミティブ型のリテラル

論理型

論理型のリテラルはtruefalseの2つ。

整数型

int/short/byte

各基数による表現

intの範囲以内の整数は10進、2進、8進、16進で表現可能。

8進表現は頭に’0‘を付ける。以下の表現は8進で表現できない値を指定していることになって、エラーになる。10進や16進表現で要注意。

  • 0809→範囲外
  • 0a0bなど→構文エラー
基数 範囲
10進 63 -2147483648~2147483647
2進 0b111111 0b0
0b11111111111111111111111111111111
8進 077 00037777777777
16進 0x3f 0x00ffffffff

整数系のリテラルは、各型で表現できる範囲とビットパターンとの関係で注意が必要。

たとえばbyte型の表現範囲は−128~127で、当然以下のような代入は可能だが、これを超える値は代入できない。

一方、2進や16進で表現した場合のリテラルは、型によって解釈の仕方が変わるため、代入結果の値に注意が必要。

たとえば2進数0b1111|1111(16進数0xff)は、byte型なら2の補数表現で−1、short型やint型など9ビット以上を扱えるなら、9ビット目以上が0で埋められて255となる。

最上位ビットが8ビット目や16ビット目でそれが1の場合、正数で解釈できる型になり、敢えて補数でマイナス表現としたいときには(byte)などでキャストする必要がある。

符号

各表現に+/-をつけることができて、−をつけると負数になる。

各基数による表現を正規表現で表すと以下のような感じか。

10進 ^[+-]?[1-9][0-9]*$(ただし範囲内)
2進 ^[+-]?0b0*1[01]{0,31}$
8進 ^[+-]?0+[1-4]?[0-7]{0,10}$
16進 ^[+-]?0x0*[0-9A-Fa-f]{0,8}$

long

long型の整数は末尾にl/Lをつける。

  • int型の範囲内の数でも末尾にLをつけるとlong型になる
  • int型の範囲を超える数は末尾にLが必須。

8進表記の不思議

8進数の場合が不規則。以下の様に2進表記の32ビットを3ビットごとに区切れば8進表示となる。

0b01|11-1|111|-111|1-11|11-1|111|-111|1-11|11-1|111
= 017777777777

0b11|11-1|111|-111|1-11|11-1|111|-111|1-11|11-1|111
= 037777777777

これから、8進表示の整数リテラルの上限は037777777777(10進で−1)となりそうだが、実際には047777777777まで通る。

実数型

double/float

Javaの実数型は浮動小数点形式のfloatdoubleの2つ。

小数点表示をした場合はdoubleとして解釈され、これにfをつけるとfloatで解釈される。

小数点と整数部か小数部のいずれかがあれば実数型に解釈される。

整数表現にfをつけるとfloatdをつけるとdoubleに解釈される。

文字型

char

文字指定

文字リテラルは、1文字をシングルクォート(')で囲む。全角文字もそのまま。2文字以上はエラー。

ダブルクォートで囲まれた場合は文字列(String)であり、char型ではない。charはプリミティブ型、Stringは参照型なのでキャストもできない。

エスケープ

シングルクォートや改行コード、タブコードなどの特殊文字はエスケープして定義する。

ユニコード指定

文字リテラルは、ユニコードのコードポイントでも指定可能。その場合、シングルクォートの中で\uでコードポイントを指定する。

ただしシングルクォートのコードポイント\u0027を指定すると文字定数が無効のエラーになる。ユニコードがコンパイルされたときに'''というリテラルになるためか。

 

Java – プリミティブ型

論理型

boolean

true/falseの二値。2値を表すのには1ビットで十分だが、実装上の内部表現については明確に定められていないらしい。

  • リテラル表現はtruefalse
  • 比較式の評価結果は論理値を持つ
  • 他の型へはキャストできない

数値型(整数型)

byte

8ビットの符号付き2進数で表現可能な整数で、範囲は−128~127。内部表現のサイズは1バイト。

  • byte型で表現可能な最大値127を超えると8ビット目が1となって負数になる
  • byte型で表現された−1(0b11111111)の演算結果がこれを超える場合、9ビット目以上が無視される
  • 符号なしで8ビット目が1となるリテラル(0b10000000x80)以上の数はint型で解釈され、byte型へのキャストが必要
    • 8ビット目が1のリテラルをbyte型にキャストした場合、負数とみなされる

short

16ビットの符号付き2進数で表現可能な整数で、範囲は−32768~32767(約3万)。内部表現のサイズは2バイト。

  • short型で表現可能な最大値32767を超えると16ビット目が1となって負数になる
  • short型で表現された−1(0bffff)の演算結果がこれを超える場合、17ビット目以上が無視される
  • 符号なしで16ビット目が1となるリテラル(0x8000)以上の数はint型で解釈され、short型へのキャストが必要
    • 16ビット目が1のリテラルをshort型にキャストした場合、負数とみなされる

int

32ビットの符号付き2進数で表現可能な整数で、範囲は−2147483648~2147483647(約21億、109オーダー)。内部表現のサイズは4バイト。

  • int型で表現可能な最大値2147483647を超えると最上位ビットが1となって負数になる
  • int型で表現された−1(0bffffffff)の演算結果がこれを超える場合、33ビット目以上が無視される
  • 符号なしで32ビット目が1となるリテラル(0x80000000)以上の数は、そのままint型の負数として解釈される

long

64ビットの符号付き2進数で表現可能な整数で、範囲は−9223372036854775808~9223372036854775807(約920京、1018オーダー)。内部表現のサイズは8バイト。

  • 与えるリテラルが16ビット以内の数値の場合、int型で解釈され、負数の場合は負数として64ビットに拡張される
  • 与えるリテラルが17ビット以上の数値の場合、リテラルには末尾にL/lを付ける必要がある
  • 与えるリテラルが65ビット以上の数値を扱うことはできない
  • long型で表現可能な最大値9223372036854775807を超えると最上位ビットが1となって負数になる
  • long型で表現された−1(0bffffffffffffffff)の演算結果がこれを超える場合、65ビット目以上が無視される

数値型(実数型)

float

32ビット(4バイト)の浮動小数点数で、−3.4028235×1038~−1.4×10−45、1.4×10−45~3.4028235×1038の範囲の実数を扱える。

  • 内部表現はIEEE754、符号1ビット、指数部8ビット、仮数部23ビット
  • 最大値はFloat.MAX、最小値はFloat.MINで取得できる
  • 最大値を超える値はInfinity、絶対値が最小値を下回る値は0.0となる

double

64 ビット(8バイト)の浮動小数点数で、−1.7976931348623157×10308~−4.9×10−324、4.9×10−324~1.7976931348623157×10308の範囲の実数を扱える。

  • 内部表現はIEEE754、符号1ビット、指数部11ビット、仮数部52ビット
  • 最大値はDouble.MAX、最小値はDouble.MINで取得できる
  • 最大値を超える値はInfinity、絶対値が最小値を下回る値は0.0となる

文字型

char

16ビットのユニコード1文字を扱う。シングルクォートで囲んだ1文字のほか、ユニコードなら\u0000\uffff、10進数なら0~65535。

 

MySQL – CSVファイルのインポートでエラー

概要

MySQLでデータベースにCSVファイルをインポートしようとしたときに以下のようなエラーが出た。

MySQLのバージョンが新しいと出るらしく、メッセージにあるようにサーバーとクライアントの双方で許可を与える必要があるそうだ。

手順

クライアント側の指定

mysqlのログイン時にオプションでローカルの入力ファイルを許可する。オプションの書き方は以下2通りのいずれか

  • --enable-local-infile
  • --local_infile=1またはon

これを設定しておかないと、後述のグローバルパラメーターを有効にしても、LOAD DATA実行時に以下のようなエラーが出る。

サーバー側の指定

MySQLにログイン後、以下のコマンドでサーバーのlocal_infileの設定を確認すると0(無効)になっている。

local_infileを有効にして、設定が反映されていることを確認。

読み込み成功

 

論理演算

記号定義

以降の議論で以下の様に記号を定義する。

  • 変数Aの否定(not)→\overline{A}
  • 変数ABの論理積(and)→ABまたはA \cdot B
  • 変数ABの論理和(or)→A + B
  • 変数ABの吐いた論理和(xor)→A \oplus B

基本演算の真理値表

not/and/or

not、and、orの真理値表は以下のとおり。T、FはTrue(真)、False(偽)を表す。

     \begin{align*} \begin{array}{c|c} A & \overline{A} \\ \hline T & F \\ F & T \end{array} \qquad \begin{array}{cc|cc} A & B & AB& A+B \\ \hline T & T & T & T\\ T & F & F & T\\ F & T & F & T\\ F & F & F & F\\ \end{array} \end{align}

排他論理和(exclusive or)

2つの変数の真偽値が「異なるときに真、同じ時に偽」となる演算。

     \begin{align*} \begin{array}{cc|c} A & B & A \oplus B \\ \hline T & T & F \\ T & F & T \\ F & T & T \\ F & F & F \end{array} \end{align}

各種法則

基本

(1)    \begin{align*} \overline{\overline{A}} = A ,\quad \begin{array}{c} AA = A \\ A \overline{A} = F \end{array} ,\quad \begin{array}{c} A + A = A \\ A + \overline{A} = T \end{array} \end{align*} \begin{align*} \begin{array}{l} AT =A \\ AF =F \end{array} \quad \begin{array}{l} A + T = T \\ A + F = A \end{array} \end{align*}

交換法則

(2)    \begin{align*} AB = BA \quad A + B = B + A \end{align*}

結合法則

(3)    \begin{gather*} (AB)C = A(BC) \\ (A + B) + C = A + (B + C) \end{gather*}

<確認>

     \begin{align*} \begin{array}{ccc|cc|cc} A & B & C & AB & (AB)C & (BC) & A(BC)\\ \hline T & T & T & T &T & T & T\\ T & T & F & T & F & F & F\\ T & F & T & F & F & F & F\\ T & F & F & F & F & F & F\\ F & T & T & F & F & T & F\\ F & T & F & F & F & F & F\\ F & F & T & F & F & F & F\\ F & F & F & F & F & F & F\\ \end{array} \end{align} \begin{align*} \begin{array}{ccc|cc|cc} A & B & C & A+B & (A+B)+C & (B+C) & A+(B+C)\\ \hline T & T & T & T & T & T & T\\ T & T & F & T & T & T & T\\ T & F & T & T & T & T & T\\ T & F & F & T & T & F & T\\ F & T & T & T & T & T & T\\ F & T & F & T & T & T & T\\ F & F & T & F & T & T & T\\ F & F & F & F & F & F & F\\ \end{array} \end{align}

分配法則

(4)    \begin{align*} A(B + C) = AB + AC \end{align*}

<確認>

     \begin{align*} \begin{array}{ccc|cc|ccc} A & B & C & B+C & A(B+C) & AB & AC & AB+AC\\ \hline\hline T & T & T & T & T & T & T & T\\ T & T & F & T & T & T & F & T\\ T & F & T & T & T & F & T & T\\ T & F & F & F & F & F & F & F\\ F & T & T & T & F & F & F & F\\ F & T & F & T & F & F & F & F\\ F & F & T & F & F & F & F & F\\ F & F & F & F & F & F & F & F\\ \end{array} \end{align}

ド・モルガンの法則(De Morgan’s laws)

ド・モルガンの法則はandとorの相互変換に関するもので、論理式の変形の基本手順として使われる。

(5)    \begin{align*} \overline{A \cdot B} = \overline{A} + \overline{B} ,\quad \overline{A+B} = \overline{A} \cdot \overline{B} \end{align*}

<確認>

     \begin{align*} \begin{array}{cc|cc|cc|cc} A & B & \overline{A} & \overline{B} & \overline{A \cdot B} & \overline{A} + \overline{B} & \overline{A + B} & \overline{A} \cdot \overline{B} \\ \hline T & T & F & F & F & F & F & F \\ T & F & F & T & T & T & F & F \\ F & T & T & F & T & T & F & F \\ F & F & T & T & T & T &T & T \end{array} \end{align}

ド・モルガンの法則による式変形

変形の基本

ド・モルガンの法則を利用して論理式を変形していくのに、以下の変形手順が用いられる。

<否定の否定>

(6)    \begin{align*} \begin{array}{l} A \cdot B = \overline{\overline{A \cdot B}} = \overline{\overline{A} + \overline{B}} \\ A + B = \overline{\overline{A + B}} = \overline{\overline{A} \cdot \overline{B}} \\ \end{array} \end{align*}

<Falseとのor>

(7)    \begin{align*} A \cdot \overline{B} = A \cdot \overline{B} + A \cdot \overline{A} = A (\overline{B} + \overline{A}) \end{align*}

NANDゲート化

NANDゲートは、A、B2つの入力のandのnotを出力するゲートで、任意の論理回路をNANDゲートの組み合わせで実装できる(完全性:completeness)。

例えばnot、and、or、xorの基本演算を、ド・モルガンの低利で変形してNANDゲートのみで表してみる。

(8)    \begin{gather*} \overline{A} = \overline{A \cdot A} \\ A \cdot B = \overline{\overline{A \cdot B}} \\ A + B = \overline{\overline{A + B}} = \overline{\overline{A} \cdot \overline{B}} \end{gather*}

これらをゲート図で表すと以下のようになる。

真偽表の変換

変換の考え方

排他論理和(XOR)の演算をNANDゲートで構成することを考える。ABに対するTrue、Falseの組み合わせのうち結果がTrueとなるものだけを抜き出すと、(A, B) = (T, F), (F, T)。それぞれの入力に対して結果がTrueとなるためには以下のいずれか満たされる必要がある。

(9)    \begin{equation*} \left\{ \begin{array}{l} A \cdot \overline{B} = T \\ \overline{A} \cdot B = T \end{array} \end{equation*}

これらのいずれかが成立すれば(左辺の論理和を取れば)Trueの結果となり、Falseとなる結果は論理和をとっても変わらないので、XORの出力は以下のように表現される。

(10)    \begin{equation*} A \oplus B = A \cdot \overline{B} +\overline{A} \cdot B \end{equation*}

この式に真偽値表の組み合わせを入れると、XORの結果になることが確認できる。

NANDゲートへの変換1

この式をド・モルガンの定理を使って変形すると以下のようになる。

(11)    \begin{align*} A \cdot \overline{B} +\overline{A} \cdot B &= \overline{\overline{A \cdot \overline{B} +\overline{A} \cdot B}} \\ &= \overline{ \overline{A \cdot \overline{B}} \cdot \overline{\overline{A} \cdot B}} \end{align*}

真理値表の確認。

     \begin{gather*} \begin{array}{cc|cc|cc|c} A & B & \overline{A} & \overline{B} & \overline{A \cdot \overline{B}} & \overline{\overline{A} \cdot B} & \overline{ \overline{A \cdot \overline{B}} \cdot \overline{\overline{A} \cdot B}}\\ \hline T & T & F & F & T & T & F \\ T & F & F & T & F & T & T \\ F & T & T & F & T & F & T \\ F & F & T & T & T & T & F \end{array} \end{gather}

式(11)をNANDゲートによる回路図で表すと以下の通り。2つのNOTはNANDゲートで作ることができ、5つのNANDゲートを使う。

NANDゲートへの変換2

一方、式(11)の2つのNANDの中を以下のように変形する。

(12)    \begin{align*} A \cdot \overline{B} &= A \cdot \overline{B} + A \cdot \overline{A} = A \cdot (\overline{A} + \overline{B}) = A \cdot \overline{A \cdot B} \\ \overline{A} \cdot B &= \overline{B} \cdot B + \overline{A} \cdot B = (\overline{A} + \overline{B}) \cdot B = \overline{A \cdot B} \cdot B \end{align*}

これらにより、XORは以下のようにも表せる。

(13)    \begin{align*} A \cdot \overline{B} +\overline{A} \cdot B &= \overline{ \overline{A \cdot \overline{B}} \cdot \overline{\overline{A} \cdot B}} \\ &= \overline{\overline{A \cdot \overline{A \cdot B}} \cdot \overline{\overline{A \cdot B} \cdot B}} \end{align*}

式(12)をNANDゲートによる回路図で表すと以下の通り。式(11)の場合に比べてNANDゲートが4つですむ。

 

Rails – ページネーション~kaminari

概要

Gemのkaminariを利用してページネーションを実装する手順。最も基本的な手順は以下の通り。

  • kaminariをインストールする
  • コントローラーにpageメソッドを記述
  • ビューにpaginateメソッドを記述

基本手順

kaminariのインストール

Gemfileに以下の1行を追加し、bundle install

準備

ダミーデータの準備

200個のPostデータをページネートすることとし、seeds.rbで初期データを生成する

標準の表示

コントローラー

ビュー

この状態だと、200個の投稿データが全て表示され、スクロールしなければならなくなる。

ページネーションの追加

コントローラーで、表示するモデルデータにpageメソッドとperメソッドを追加。

  • kaminariによってparamsにビューで表示しているページが追加される
  • pageに引数として表示させるページを渡す
  • perで1ページあたりの表示数を指定する

ビューにpagenateメソッドを追加し、ページ操作の表示をさせる。

 

Rails – データベースの初期データ

概要

Railsで準備されているseeds.rbファイルを使って、データベースの初期データを準備する手順。

Railsであらかじめdbディレクトリー下にseeds.rbファイルが準備されている。

このファイルに初期データをセットするコードを書き、コンソールでrails db:seedを実行すると、そのコードが実行される。

操作例

たとえばPostモデルで200件のダミーデータを準備する場合。

Postモデル

commentフィールドだけを持つPostモデルを準備する。

seeds.rbファイル

seeds.rbファイルに、200個のPostデータを書き込むコードを書く。

db/seeds.rb

Railsコマンド実行

以下のRailsコマンドでseeds.rbファイルを実行し、データベースにデータを書き込む。

結果

以下のとおりデータが書き込まれる。

 

Ruby – 配列・ハッシュの生成・変換

配列の生成

同じ値で埋める

連番の配列

数列の配列

乱数の配列

ハッシュから配列への変換

キーや値の配列を取り出す

シンボルの配列を文字列の配列に変換するにはto_s、その逆の変換はto_symを要素にマップする。

[キー, 値]を要素とする配列に変換

[[キー, ...], [値, ...]]の配列に変換

配列からハッシュへの変換

基本の生成方法

ただし配列をそのまま適用するとエラー。

なので以下を利用する。

フラットな配列からハッシュへ

*を利用して展開

[[キー, 値], ...]の配列から変換

フラットな配列に変換してからハッシュへ。

[[キー, ...], [値, ...]]の配列から変換

transpose[[キー, 値], ...]の形にしてからフラットな配列に変換して展開。

キー配列と値の配列から変換

[キー配列, 値配列]からtranspose→flatten→展開。

to_hを使う方法

[[キー, 値], ...]の配列ならHash[*a.flatten]とせずにa.to_hが使える。上のそれぞれの配列についてto_hを使うと以下のようになる。

補足~シンボルと文字列の変換

シンボルと文字列の配列はto_s、to_symで相互変換可能。

 

Rails – ファイルのアップロード~Carrierwave

概要

ファイルのアップロードをGemのCarrierWaveで簡単にする手順。

  • CarrierWaveをインストールする
  • Uploaderを生成する
  • モデルのファイル名プロパティーとUploaderを関連付ける

あとはfile_fieldから選択されたファイルをパラメーターに含むモデルでsaveuploadなど実行すれば、実体ファイルもそれに連動して操作される。

アップロードファイルのパラメーターが複数でも、1つのアップローダーで対応できる。

手順

要件

  • nameimage1image2の3つのstring属性を持つUserモデルに画像をアップロードする
  • データベースのカラムもこれに対応したVARCHARタイプの3つ

CarrierWaveの導入

Gemfileに以下の1行を追加。

Railsサーバーを止めてbundle install後、サーバーを再起動

Uploaderクラスの生成

Railsコマンドでアップローダークラスを生成する。この例ではUserImageUploaderとしている。

この操作によって、以下のディレクトリーとファイルが追加される。

app/uploaders/user_image_uploader.rb

モデルとDB

UserモデルとDBを結ぶマイグレーションファイルは以下のとおりで、画像ファイルのファイル名を保持するフィールドを2つ持っている。

モデルパラメーターとの関連付け

モデルクラスのファイルにmount_uploaderの1行を追加し、パラメーターとアップローダーを関連付ける。ここではimage1image2UserImageUploaderを関連付けている。

app/models/user.rb

コントローラー

コントローラーではアップローダーを特に意識する必要はない。

今回の例では、既にデータが登録されているusersテーブルの先頭データを取り出し、画像パラメーターを更新している。

ビュー

ビューでもCarrierWaveを意識する必要はない。ここでは画像更新機能として以下の2つを実行している。

  • file_fieldで指定されたアップロード画像をコントローラーにPOST
  • アップロード画像が存在していれば表示

エラー対応

当初、NameError uninitialized-constantが発生。下記1行をapplication.rbに追加してエラーは出なくなったが、なぜapp下のuploadersが自動で読み込まれないのか不明。

config/application.rb

ファイルの保存場所

デフォルトでは以下の場所に保存される。

アップロードファイル
public/uplodads/モデル名/属性名/:id
テンポラリーファイル
public/uploads/tmp

たとえば今回の例でid=1のユーザーのファイルは以下の様に保存される。ファイルを更新すると、前のファイルは削除される。

各種設定

概要

ファイルの保存場所やファイル名の付け方などの設定は、rails g uploderで生成したアップローダーのファイルに書かれている。

app/uploader/user_image_uploader.rb

ファイル保存場所

媒体

storageでローカルファイルへの保存を指定。fogはクラウドサービス用のGem。

パス

def store_dirでファイルを保存するディレクトリーのパスを設定。

ファイル名

デフォルトではここはコメントアウトされていて、アップロード時のオリジナルファイル名が使われる。以下の様にコメントを外すと、ファイル名が全てsomething.jpgに固定される。

ここでランダム文字列などのUUIDを使うとユーザーごとにディレクトリーを分けなくてもよくなりそうだが、CarrierWave内でファイル種別を取得する必要がある(とりあえず先送り)。

ファイル拡張子

以下の部分のコメントを外すと、指定した拡張子のファイル以外はアップロードされず、データベース処理もロールバックされる。

ただし明示的なエラーは発生しなかった。

 

Rails – erbファイルでの改行の反映

概要

  • \nなどの改行コードを含む文字列をhtml.erbファイルで表示させると改行が反映されない
  • 改行コードを<br>に置換してhtml_safeで表示させると改行は反映される
  • しかしながら、この場合は他の特殊文字もそのまま表示されるのでXSSに対して脆弱
  • そこで以下の手順をとる
    1. まず特殊文字をエスケープ
    2. 改行コードを<br>に変換
    3. html_saferawで表示

改行コードは反映されない

改行コードを含む文字列をerbファイル中<%= ... %>で表示させても、HTMLで解釈されないので改行されない。

<br>タグに変換してもエスケープされる

erb側のセキュリティー対策のため、HTMLの特殊文字はエンティティ―でエスケープされる。なので改行コードを<br>に変換するとそのままタグが表示される。

html_safeやrawならタグとして機能する

html_saferawを使うと、タグをタグとして解釈してくれる。

この場合XSSに対して脆弱

ただし上記の方法では、<br>以外のタグも機能してしまうので、XSSに対して脆弱。

エスケープしてから改行コードを変換

以下の手順なら、改行コードから変換された<br>以外はエスケープされる。

  1. まずh関数で特殊文字をエスケープ
  2. その後改行コードを<br>タグに置換
  3. その結果をhtml_saferawで表示させる

ヘルパーにしておくと便利

上記の処理をヘルパーとして定義しておくと汎用的に使える。