数値の桁数を揃える

整数の桁数をそろえる

 数字の桁数を揃えて文字列に変換したいということは、色々な場面であると思います。
 まず、日付など1〜2桁のもので、1桁のものは頭に0を付けたい場合は。以下のように、数値の頭に文字列の"0"を加えて文字列化し、文字列の最後から2キャラクターを取り出すことで、2桁に揃えます。

set theDay to 2
set theDay to text -2 thru -1 of ("0" & theDay)

 日付で無い場合は、もう少し桁が多い場合もあるでしょう。例えば8桁までの整数があって、足りない分の桁には"-"を入れたいという場合は、先ほどのスクリプトを応用して、以下のようにします。

set theNum to 10000
set theNum to text -8 thru -1 of ("--------" & theNum)

小数点以下も揃える

 整数の場合は、先ほどのやり方で問題ありませんが、小数点以下が存在する場合の桁揃えは、もう少し複雑になります。
 要は、整数部分と、小数点以下の部分を分離して、それぞれに処理をすればいいのです。以下のハンドラの場合は、整数5桁、小数点以下3桁で処理しています。

numChopper(150.56)

on numChopper(theNum)
	set tmp to text item delimiters
	set theNum to (theNum as string) & ".0" -- 整数であった場合のために".0"を追加しておく
	set text item delimiters to "."
	set {theUpper, theDowner} to text items of theNum -- "."で前後に分割
	set text item delimiters to tmp
	
	set theUpper to text -5 thru -1 of ("0000" & theUpper)
	set theDowner to text 1 thru 3 of (theDowner & "00")
	return theUpper & "." & theDowner
end numChopper

 上の例では、text item delimitersを利用しましたが、今度はdevとmodを利用して、整数と小数点以下に分けています。

numChopper(150.56)

on numChopper(theNum)
	set theUpper to text -5 thru -1 of ("0000" & (theNum div 1))
	set theDowner to text 2 thru 4 of ((1 + (theNum mod 1)) * (10 ^ 3) as string)
	return theUpper & "." & theDowner
end numChopper

 まず、整数部分ですが「theNum div 1」とすることで、小数点以下を無くすことができます。その後は、先ほどと同じ"0"を付け加える処理です。
 divを使わずにOSAX命令のroundを使って「round theNum rounding down」としても構いませんが、多少スピードが落ちる上に、書くのが面倒ですから、ここでは無理に使う理由は無いでしょう。詳しくは「数値を丸める」の項を参照して下さい。
 次に、小数点以下の部分は「theNum mod 1」で小数点以下を取り出します。
 ここで1を加えているのは、その後のかけ算で桁が上がらないと困るので、ダミーとして1を加えているわけです。ダミーなので1でなくても2でも3でも構いません。
 さらに値に10^3を掛けることによって、桁を3つ上げます。10^3は1000でもいいのですが、3桁あげるということが分かりやすいように10^3を使っています。
 最後に文字列に変換した後、2〜4つめの文字を取り出しています。1つめはダミーなので、飛ばすわけです。
 このようにややこしい過程を辿りますが、スクリプトは逆に短くなります。

指数の処理

 少なめの数なら問題ありませんが、大きな数になるとAppleScriptは数字を指数表記し始めます。
 そうなると今までの方法は使えません。そこで、指数表記をされるような大きな数を文字列に変換します。

real2Str(1.51252E+13)

on real2Str(theNum)
	set theNum to theNum as string
	if "E" is not in theNum then return theNum -- 指数表記で無い場合は処理しない

	-- 単語区切りを利用し 数値E, +, 指数 に分ける
	set {x, ope, e} to words of theNum
	-- 必ず2つめに小数点が来るので、それを利用し小数点を取り除く
	set x to (character 1 of x) & (text 3 thru -2 of x)
	-- ゼロを付加する
	set zeros to e-(length of x)+1
	repeat zeros times
		set x to x & "0"
	end repeat
	return x
end real2Str

 逆に極端に小さな値の場合も指数表記になりますので、そちらも処理します。

real2Str(1.51252E-5)

on real2Str(theNum)
	set theNum to theNum as string
	if "E" is not in theNum then return theNum -- 指数表記で無い場合は処理しない
	
	-- 単語区切りを利用し 数値E, 指数 に分ける
	set {x, e} to words of theNum
	-- 必ず2つめに小数点が来るので、それを利用し小数点を取り除く
	set x to (character 1 of x) & (text 3 thru -2 of x)
	-- ゼロを付加する
	repeat e - 1 times
		set x to "0" & x
	end repeat
	return "0." & x
end real2Str

 指数表記かどうかの判定の後、+か-の符号が含まれていることを確認して場合分けし、上記の二種類の方法を適用し、数値が負であった場合も考慮に入れると、最終的に以下のようなハンドラになりました。
 んー、ちょっとことが大袈裟になりすぎたような。もう少し簡単に書けそうな気がする。

real2Str(-1.51252E-8)

on real2Str(theNum)
	-- 正負で、以降の処理を同じにするため、符号を記録し、負の場合は正に反転する
	if theNum >= 0 then
		set ope to ""
	else
		set ope to "-"
		set theNum to -theNum
	end if
	
	set theNum to theNum as string
	if "E" is not in theNum then return ope & theNum -- 指数表記で無い場合は処理しない
	
	-- "E"を区切りに分割
	set tmp to text item delimiters
	set text item delimiters to "E"
	set {x, e} to text items of theNum
	set text item delimiters to tmp
	
	-- 必ず2つめに小数点が来るので、それを利用し小数点を取り除く
	set x to (character 1 of x) & (text 3 thru -1 of x)
	-- ゼロの数を求めるための前処理
	set e to e + 1
	if e > 0 then
		-- ゼロを付加する(大きい数の場合)
		repeat e - (length of x) times
			set x to x & "0"
		end repeat
	else
		-- ゼロを付加する(小さい数の場合)
		repeat -e times
			set x to "0" & x
		end repeat
		set x to "0." & x
	end if
	-- 符号を付けて、値を返す
	return ope & x
end real2Str

3桁ごとに区切りを入れる

 桁が多くなると、適当に区切りを入れた方が見やすいのは常識です。
 それを自動化してみましょう。real2strは、先ほど作ったハンドラです。
 普通は、正の整数に3桁ごとでしか区切りを入れませんから、それに対応したハンドラにします。特に変則的な処理はしていません。

delimitNum of (real2str(1.51252E+8)) 

on delimitNum of theStr
	set lengthOfStr to length of theStr
	set restOfStr to (lengthOfStr mod 3)
	
	-- リストに3区切りで文字列を取り出す
	set theList to {}
	repeat with i from lengthOfStr to (x + 1) by -3
		set beginning of theList to text (i - 2) thru i of theStr
	end repeat
	-- 3で割り切れずあまった部分を追加
	if restOfStr > 0 then set beginning of theList to text 1 thru restOfStr of theStr

	-- ","を区切りごとに挿入
	set tmp to text item delimiters
	set text item delimiters to ","
	set theStr to theList as string
	set text item delimiters to tmp
	
	return theStr
end delimitNum

 これらの桁揃えなどの処理は、AppleScript以外の言語では普通に持っているものなので、どうにか標準で用意して欲しいところです。
 見ての通り、たいしたプログラムでは無いので、OSAXではなく本体に実装して欲しいと思います。
 とりあえずは、Tanaka's osaxのMT Digit Stringを使えば一撃です。


2000-03-29 -2000-05-31