7. 項目間演算

mcalmsel は項目間の演算を行うことを主目的に開発された処理メソッドある。 項目間演算として100 以上の関数/演算子が実装されており、 それらを組み合わせることで多様な処理を実現できるようになっている。

7.1. 式の構成要素

項目間演算で記述する式を構成する要素は、定数、項目値、演算子、関数の4つに大きく分類できる。 そして、それぞれの要素において、ユーザはデータ型を意識して利用する必要がある。 mcmdの処理メソッドではデータは全て文字列として与えらており、 それら文字列を 項目間演算 でどのようなデータ型として扱うかはユーザに委ねられているからである。 項目間演算で扱えるデータ型は文字列型(str),数値型(num)、日付型(date)、時刻型(time)、論理型(bool)の5つである。 以下では、式を構成するそれぞれの要素で、5つのデータ型をどのように扱うかを示す。

7.2. 定数

表 7.1 定数の書式一覧

データ型

書式

内容

数値( \(num\) )

整数、実数の文字列表記

内部的には全て倍精度実数を利用

20  0.55  1.5*e10

文字列( \(str\) )

文字列

ダブルクオーテーションで括った文字列

"abc" "日本語"

日付( \(date\) )

0dyyyymmdd

先頭に"0d"を付けた年月日固定長

0d20080923

時刻( \(time\) )

0tyyyymmddHHMMSS

先頭に"0t"を付けた年月日時分秒固定長

0t20080923121115

0tHHMMSS

先頭に"0t"を付けた時分秒固定長(内部的に本日の日付が補完される)

0t121115

論理( \(bool\) )

0b1 0b0

先頭に"0b"を付けた"1"(true)もしくは"0"(false)

0b1  0b0

7.3. 項目値

データ上の項目名を指定するには 表 7.2 に示される通り、 データをどのデータ型として扱うかによって異なってくる。 データは全て文字列データであるために、それらをどのような型のデータとして扱うかはユーザの判断に任されている。

表 7.2 項目値の書式一覧

データ型

書式

CSVデータ内容

数値(num)

${項目名}

整数、実数(指数表現含む) の文字列表記

${amount}

文字列(str)

$s{項目名}

文字列

$s{gender}

日付(date)

$d{項目名}

年月日固定長(yyyymmdd)

$d{date}

時刻(time)

$t{項目名}

年月日時分秒の固定長(yyyymmddHHMMSS)

$t{time}

時分秒(HHMMSS)の固定長(内部的に本日の日付が補完される)

論理(bool)

$b{項目名}

項目値の一文字目が"1"の時にtrue、"0"の時にfalse、その他の場合にはNULLと解釈される。

$b{condition}

項目名にはワイルドカードを指定することができる。 例えばsum関数は複数の数値項目の合計を計算する関数であるが、 ワイルドカードを指定することで、多数の項目を一つのワイルドカードで指定することも可能となる。 例えば、入力データとして A1,A2,A3 の3つの数値項目名があったとすると、 sum(${A*}) とすれば、 A1,A2,A3 の合計値を計算してくれる。 sum(${A*},${B*}) のように複数のワイルドカードを指定することも可能である。

7.4. 前行の項目値

項目値の指定に $ の代わりに # を指定すると、前行の項目値となる。 ただし、先頭行は前行がないのでNULLとなる。 各データ型における指定方法を 表 7.3 に示す。

表 7.3 前行の項目値の書式一覧

データ型

書式

数値(num)

#{項目名}

#{amount}

文字列(str)

#s{項目名}

#s{gender}

日付(date)

#d{項目名}

#d{date}

時刻(time)

#t{項目名}

#d{time}

論理(bool)

#b{項目名}

#b{condition}

7.5. 前行の結果項目値

前行項目の指定において項目名を省略すると前行の計算結果項目の値となる。 各データ型における指定方法を 表 7.4 に示す。 if関数とtop()関数とを組み合わせる事で、累計計算などが可能となる。 以下に、金額項目の累計計算例を示す。

mcal c='if(top(),${price},${price}+#{})' a=accum

表 7.4 前行の結果項目値の書式一覧

データ型

書式

数値(num)

#{}

#{}

文字列(str)

#s{}

#s{}

日付(date)

#d{}

#d{}

時刻(time)

#t{}

#d{}

論理(bool)

#b{}

#b{}

7.6. 算術演算子

+=True などの算術演算子は数値型だけでなく、文字列型や日付型のデータに対しても定義されている。 それらの一覧を 表 7.5 に示す。

表 7.5 算術演算子一覧

演算子

書式

内容

加算(+)

\(num_1+num_2\)

数値の足し算

1.5+2.3 (3.8)

\(str_1+str_2\)

文字列の結合

"150"+"円" ("150円")

\(date+num\)

\(num\) 日後の日付

0d20121130+2 (0d20121202)

\(time+num\)

\(num\) 秒後の時刻

0t095959+2 (0t100001)

減算(-)

\(num_1-num_2\)

数値の引き算

1.5-2.3 (-1.8)

\(str_1-str_2\)

部分文字列の削除

"aababa"-"a" ( "bb" )

(貪欲マッチによる)

"aababa"-"aba" ( "aba" )

\(date-num\)

\(num\) 日前の日付

0d20121202-2 (0d20121130)

\(time-num\)

\(num\) 秒前の時刻

0t100001-2 (0t095959)

\(date_1-date_2\)

日付差

0d20121202-0d20121130 (2)

\(time_1-time_2\)

時刻差

0t095959-0t100001 (-2)

乗算(*)

\(num_1*num_2\)

掛け算

10*2 (20)

除算(/)

\(num_1/num_2\)

割り算

10/2 (5)

剰余(%)

\(num_1\%num_2\)

剰余

10%3 (1)

累乗(^{})

\(num_1\) ^{} \(num_2\)

累乗

10^3 (1000)

7.7. 比較演算子

比較演算は同一のデータ型の値同士でのみ適用可能である。 全てのデータ型に共通した書式であり、以下では数値型についてのみ(例では文字型につても) 表 7.6 に示す。 文字型、日付型、時刻型においても同様に利用できる。

表 7.6 比較演算子一覧

比較内容

書式

等しい

\(num_1==num_2\)

1.5==1.5(0b1)  "abc"=="abcd" (0b0)

等しくない

\(num_1!=num_2\)

1.5!=1.5(0b0)  "abc"=="abcd" (0b1)

より大きい

\(num_1>num_2\)

10>5(0b1)  "abc">"abcd" (0b0)

より小さい

\(num_1<num_2\)

10<5(0b0)  "abc"<"abcd" (0b1)

以上

\(num_1>=num_2\)

10>=10(0b1)  "a">"" (0b1)

以下

\(num_1<=num_2\)

8<=9(0b1)  "a"<="a" (0b1)

7.8. 論理演算子

3つの論理演算子(論理積、論理和、排他的論理和)が利用でき、それぞれの書式を 表 7.7 に示す。 また、それぞれの演算における真偽(1:真,0:偽)の組み合せとその結果を 表 7.8 , 表 7.9 , 表 7.10 に示す。

表 7.7 論理演算子一覧

内容

書式

論理積

\(bool_1\) && \(bool_2\)

"abc"=="abc" && "xyz"=="abc" (0b0)

論理和

\(bool_1\) || \(bool_2\)

"abc"=="abc" || "xyz"=="abc" (0b1)

排他的論理和

\(bool_1\) ^^ \(bool_2\)

"abc"=="abc" ^^ "xyz"=="abc" (0b1)

表 7.8 論理積

\(bool_1\)

\(bool_2\)

結果

1

1

1

1

0

0

0

1

0

0

0

0

null

1

null

null

0

0

null

null

null

表 7.9 論理和

\(bool_1\)

\(bool_2\)

結果

1

1

1

1

0

1

0

1

1

0

0

0

null

1

1

null

0

null

null

null

null

表 7.10 排他的論理和

\(bool_1\)

\(bool_2\)

結果

1

1

0

1

0

1

0

1

1

0

0

0

null

1

null

null

0

null

null

null

null

演算子(後述)の優先順位は 表 7.11 に示すとおりである。 同一の演算子間の優先順位は出現順序による。 優先順位を変更するときは括弧を利用すれば良い。

表 7.11 演算子の優先順位(version 0.3.12以降に累乗演算子^の優先順位を1段階上げた)

優先順位

演算子

1

^

2

* / %

3

+ -

4

> < >= <=

5

== !=

6

&&

7

|| ^^

7.9. 関数

以下では、数値関連( 表 7.12 )、三角関数関連( 表 7.13 )、 文字列関連( 表 7.14 )、正規表現関連( 表 7.15 )、 日付時間関連( 表 7.16 )、論理関数( 表 7.17 )、 行/項目情報関連( 表 7.18 )、NULL値関連( 表 7.19 )、 そして型変換関連( 表 7.20 )の9つに分けて解説する。

表 7.12 数値関連関数一覧

関数名

パラメータ

出力型

sum 合計

sum( \(num_1 num_2 \cdots\) )

\(num\)

avg 平均

avg( \(num_1 num_2 \cdots\) )

\(num\)

sqsum 平方和

sqsum( \(num_1 num_2 \cdots\) )

\(num\)

min 最小値

min( \(num_1 num_2 \cdots\) )

\(num\)

max 最大値

max( \(num_1 num_2 \cdots\) )

\(num\)

product 積

product( \(num_1 num_2 \cdots\) )

\(num\)

factorial 階乗

factorial( \(num\) )

\(num\)

gcd 最大公約数

gcd( \(num_1\) \(num_2\) )

\(num\)

lcm 最小公倍数

lcm( \(num_1\) \(num_2\) )

\(num\)

sqrt 平方根

sqrt( \(num\) )

\(num\)

abs 絶対値

abs( \(num\) )

\(num\)

sign 符号

sign( \(num\) )

\(num\)

int 整数部

int( \(num\) )

\(num\)

fract 小数部

fract( \(num\) )

\(num\)

round 四捨五入

round( \(num\) 基準値)

\(num\)

floor 切り捨て

floor( \(num\) ,基準値)

\(num\)

ceil 切り上げ

ceil( \(num\) ,基準値)

\(num\)

power 累乗

power( \(num\) ,指数)

\(num\)

exp 指数関数

exp( \(num\) )

\(num\)

log 対数

log( \(num\) ,底)

\(num\)

ln 自然対数

ln( \(num\) )

\(num\)

log2 底が2の対数

log2( \(num\) )

\(num\)

log10 常用対数

log10( \(num\) )

\(num\)

dist 距離

dist(タイプ \(num_1 num_2 \cdots\) )

\(num\)

distgps GPS距離

distgps(緯度1 経度1 緯度2 経度2)

\(num\)

heron 三角形の面積

heron( \(num_1 num_2 \cdots\) )

\(num\)

rand 一様乱数

rand([乱数の種])

\(num\)

randi 整数一様乱数

randi(最小値 最大値[ 乱数の種])

\(num\)

nrand 正規乱数

nrand(平均 標準偏差[ 乱数の種])

\(num\)

pi 円周率

pi()

\(num\)

e ネイピア数

e()

\(num\)

format 書式付き出力

format()

\(str\)

表 7.13 三角関数関連関数一覧

関数名

パラメータ

出力範囲

acos コサインの逆関数

acos( \(num\) )

\(0\sim\pi\)

asin サインの逆関数

asin( \(num\) )

\(-\pi\sim\pi\)

atan タンジェントの逆関数

atan( \(num\) )

\(-\pi\sim\pi\)

atan2 座標の角度

atan2( \(num_1\) \(num_2\) )

\(-\pi\sim\pi\)

cos コサイン

cos( \(r\) )

\(-1.0\sim 1.0\)

sin サイン

sin( \(r\) )

\(-1.0\sim 1.0\)

tan タンジェント

tan( \(r\) )

\(-\infty\sim\infty\)

degree 角度

degree( \(r\) )

\(-\pi\sim\pi\)

radian ラジアン

radian(角度)

\(-\pi\sim\pi\)

cosh 双曲線余弦

cosh( \(r\) )

\(0\sim\infty\)

sinh 双曲線正弦

sinh( \(r\) )

\(-\infty\sim\infty\)

tanh 双曲線逆正接

tanh( \(r\) )

\(-1.0\sim 1.0\)

表 7.14 文字列関連関数一覧

関数名

パラメータ

出力型

cat 文字列併合

cat( \(token str_1 str_2 \cdots\) )

\(str\)

length 文字列長

length( \(str\) )

\(num\)

fixlen 固定長変換

fixlen( \(str\) 長さ 位置 padding文字)

\(str\)

right 末尾切り出し

right( \(str\) 長さ)

\(str\)

left 先頭切り出し

left( \(str\) 長さ)

\(str\)

mid 部分文字列切り出し

mid( \(str\) 開始位置 長さ)

\(str\)

toupper 大文字変換

toupper( \(str\) )

\(str\)

tolower 小文字変換

tolower( \(str\) )

\(str\)

capitalize 先頭文字大文字変換

capitalize( \(str\) )

\(str\)

match 検索

match(検索文字列 \(str_1 str_2 \cdots\) )

\(bool\)

hasspace 空白類文字検索

hasspace( \(str\) )

\(bool\)

表 7.15 正規表現関連関数一覧

関数名

パラメータ

出力型

regexm 全体マッチ

regexm( \(str\) 正規表現)

\(bool\)

regexs マッチ

regexs( \(str\) 正規表現)

\(bool\)

regexrep マッチ文字列の置換

regexrep( \(str\) 正規表現 置換文字列)

\(str\)

regexlen マッチ文字数

regexlen( \(str\) 正規表現)

\(num\)

regexpos マッチ位置

regexpos( \(str\) 正規表現)

\(num\)

regexstr マッチ文字列

regexstr( \(str\) 正規表現)

\(str\)

regexpfx マッチ文字列のプレフィックス

regexpfx( \(str\) 正規表現)

\(str\)

regexsfx マッチ文字列のサフィックス

regexsfx( \(str\) 正規表現)

\(str\)

表 7.16 日付時間関連関数一覧

関数名

パラメータ

出力型

today 本日の日付

today()

\(date\)

now 現在時刻

now()

\(time\)

tseconds 経過秒数

tseconds( \(time\) )

\(num\)

leapyear 閏年判定

leapyear( \(dt\) )

\(bool\)

year 西暦年

year( \(dt\) )

\(num\)

month 月

month( \(dt\) )

\(num\)

day 日

day( \(dt\) )

\(num\)

week 週

week( \(dt\) )

\(num\)

dow 曜日

dow( \(dt\) )

\(num\)

time 時分秒

time( \(time\) )

\(str\)

date 年月日

date( \(time\) )

\(str\)

hour 時

hour( \(time\) )

\(num\)

minute 分

minute( \(time\) )

\(num\)

second 秒

second( \(time\) )

\(num\)

age 年令

age( \(dt_1 dt_2\) )

\(num\)

diff 期間

diff( \(dt_1 dt_2\) )

\(num\)

uxt UNIX時刻変換

uxt( \(dt\) )

\(num\) (UNIX時刻)

julian ユリウス暦変換

julian( \(dt\) )

\(num\) (ユリウス通日)

表 7.17 論理関連関数一覧

関数名

パラメータ

出力型

and 論理積

and( \(bool_1 bool_2 \cdots)\)

\(bool\)

or 論理和

or( \(bool_1 bool_2 \cdots)\)

\(bool\)

not 否定

not( \(bool)\)

\(bool\)

if 条件選択

if( \(bool num_1 num_2\) )

\(num\)

if 条件選択

if( \(bool str_1 str_2\) )

\(str\)

if 条件選択

if( \(bool date_1 date_2)\)

\(date\)

if 条件選択

if( \(bool time_1 time_2)\)

\(time\)

表 7.18 行/項目情報関連関数一覧

関数名

パラメータ

出力型

line 行番号

line()

\(num\)

top 先頭行

top()

\(bool\)

bottom 終端行

bottom()

\(bool\)

fldsize 項目数

fldsize()

\(num\)

argsize 引数の数

argsize( \(str_1 str_2 \cdots\) )

\(num\)

表 7.19 NULL値関連関数一覧

関数名

パラメータ

出力型

null NULL値

nulln()

\(num\)

null NULL値

nulls()

\(str\)

null NULL値

nulld()

\(date\)

null NULL値

nullt()

\(time\)

null NULL値

nullb()

\(bool\)

isnull NULL値判定

isnull( \(num\) )

\(bool\)

isnull NULL値判定

isnull( \(str\) )

\(bool\)

isnull NULL値判定

isnull( \(date\) )

\(bool\)

isnull NULL値判定

isnull( \(time\) )

\(bool\)

isnull NULL値判定

isnull( \(bool\) )

\(bool\)

countnull 合計

countnull( \(num_1 num_2 \cdots\) )

\(num\)

countnull 合計

countnull( \(str_1 str_2 \cdots\) )

\(num\)

countnull 合計

countnull( \(date_1 date_2 \cdots\) )

\(num\)

countnull 合計

countnull( \(time_1 time_2 \cdots\) )

\(num\)

countnull 合計

countnull( \(bool_1 bool_2 \cdots\) )

\(num\)

表 7.20 型変換関連関数一覧

cast 型変換

\(num\)

\(str\)

\(date\)

\(time\)

\(bool\)

\(num\)

n2s( \(num\) )

n2b( \(num\) )

\(str\)

s2n( \(str\) )

s2d( \(str\) )

s2t( \(str\) )

s2b( \(str\) )

\(date\)

d2s( \(date\) )

d2t( \(date\) )

\(time\)

t2s( \(time\) )

t2d( \(time\) )

\(bool\)

b2n( \(bool\) )

b2s( \(bool\) )

7.10. 日付型と時刻型について

mcalでは日付時刻について2つの型を用意している。 一つは日付型で他方は時刻型である。 時刻型は時刻だけでなく日付とセットで表現する。 内部的にはグレゴリオ暦に基づいたboost C++ライブラリのdate_timeライブラリを利用しており、 日付型にはboost::gregorian::dateクラスを、 時刻型にはboost::posix_time::ptimeクラスを使っている。 詳細は http://www.boost.org/ のドキュメントを参照されたい。

dateクラスは32ビット整数で管理されており、1400年1月1日から9999年12月31日の範囲をサポートしている。 日付の演算は全てグレゴリオ暦に基づいたものとなっている。 不正な日付(例えば、2013/2/29や1399/12/31)が与えられたときはNULL値が出力される。 一方でptimeクラスは、64ビットで管理されており、ミリ秒まで扱える時刻システムであるが、 mcalコマンドにおいてはミリ秒を扱うインターフェースは備えていない。 またptimeクラスはdateクラスも内部で参照しており、日付をまたいだ時間計算を可能としている。 不正な時刻(例えば、18:62:11)が与えられたときはNULL値が出力される。

mcmdはテキストデータを扱うので、日付/時刻は、データ上は文字列で表現される必要がある。 それらの文字列を日付型および時刻型に内部で変換して各種演算を行い、最終結果を再度文字列に戻して出力している。 文字列のフォーマットは、日付型は8桁固定長文字列(例えば、 20130911 )、 時刻型は14桁固定長文字列(例えば、 20130911110528 )、 もしくは6桁固定長文字列(例えば、 110528 )を標準としている。 日付型と時刻型と各種関数の関係を 図 7.1 に示す。 2013年9月6日10時43分27秒を例に、date型とtime型と各種関数の関係を図示している。 実線で囲われたボックスは実データを表し、アンダーラインを付したものは関数等を表している。

../_images/calsel_datetime.png

図 7.1 日付型と時刻型と各種関数の関係

またユーザは日付/時刻として固定長文字列を標準とせずに、 ユリウス通日(紀元前4713年1月1日正午からの日数)やUNIX時刻(1970年1月1日00時00分00秒(GMT)からの 経過秒数)などの整数を標準の日時の表記として利用してもよいであろう。 ユリウス通日やUNIX時刻と、日付型/時刻型との変換関数も備えており、十分に運用可能である。 ただし、mcalが提供する日付/時刻関数を使う限りにおいては、内部的にはグレゴリオ暦によって管理されており、 その範囲は、1400年1月1日から9999年12月31日に限定されることに注意する。 またUNIX時刻は32ビット整数で管理されているため、2038年1月19日3時14分7秒を超えると正しく計算できないことに注意する。 ただユリウス通日やUNIX時刻を利用する欠点は、その数字を見ただけでは実際にいつの日付時刻なのか理解出来ない点にあろう。