【追記 5/28 15:00】
重大な不具合をあるふぁ(仮)さんが見つけてくださったのと、最初に書いたスクリプト(単位付き計算を行う関数)が加算以外に対応していなかったことに気づいたのでここに追記して訂正いたします。
まずあるふぁ(仮)さんからのありがたいご指摘。
誤差がプラマイ1未満ならtrueを返すというおおざっぱ仕様ですな pic.twitter.com/g0FabVnYe8
— あるふぁ(仮) (@peprintenpa) May 28, 2018
UnitValue、なんと雑な仕様なのでしょう…。泣けてきます。
UnitValueを安易に数値と比較しないほうがいいようです。
当然ですが、parseInt
やparseFloat
でUnitValueオブジェクトを数値型に変換したり、UnitValueオブジェクトからvalue
プロパティを参照すればちゃんとした数値型です。最悪このあたりを使うか、ちゃんと比較するならas
メソッドでちゃんと数値に換算した上で比較したほうがいいです。
続いてスクリプトの改訂版です。最初にアップしたものは「加算」しかできなかったので大幅に修正しました。
function (formula, as){ var regexp = /([0-9.]+)([a-z]+)*/ig; //UnitValueを利用する関数 var myUnit = function (value, unit){ if (!unit) unit = as; return new UnitValue(parseFloat(value), unit).as(unit); } formula = formula.replace(/ +/g, ""); //スペースが入っていたら削除 var newFormula = formula; //最終的な置換結果用の計算式 //find[1]:数値、find[2]:単位 while(find = regexp.exec(formula)){ var calc = myUnit(find[1], find[2]).toString(); //replaceメソッドで使うので文字列にしている newFormula = newFormula.replace(find[0], calc); } //evalメソッドで計算 return eval(newFormula); }
これ以降のこの記事は、この追記の内容を踏まえる前のものです。一部正確でない表現や勘違いがありますが、一応そのまま残しています。
ただスクリプトに関しては完全に漏れがあったのと、混同されてしまうと問題なので、修正前のスクリプトは削除しました。
訂正してお詫びいたします。
【追記 5/28 1:10】
@AJABON先生より、UnitValueでは誤差が出ることがあるかも?とご助言いただきました。
もともとJavaScriptでは小数を含む計算が苦手なこともあり*1、念のため多少の誤差が出るかもしれないという認識のもとお使いください。
ただ、UnitValueの誤差がどれほどかを試そうとしたところ、意外な発見がありました。
var result = UnitValue(20.2, "pt") - UnitValue(20, "pt"); $.writeln(result); $.writeln(0.2 === result); //true var result2 = 20.2 - 20; $.writeln(result2); $.writeln(0.2 === result2); //false
UnitValueを使うと、この計算式がtrueになったのです…。単位が付いているということでなにかご利益があるのか?w
いずれにせよ、小数の計算に役立つとは思いませんでした。とはいえ相手はJavaScriptなので、過信しないほうがいいでしょうね。
--追記ここまで--
ちょっと前に、ExtendScriptで「単位が入り混じった計算を行うスクリプト」を紹介しました。
せっかくなので、もう少し実用性のあるコードも用意してみました。単位が入り混じった計算を行うスクリプトです。
JavaScriptの検索とInDesignの検索 - DTPab
が! もっといい方法がありました。
UnitValueオブジェクトを利用する
たまたま調べ物をしていて見つけたもので、とっても便利なものでした。ほんと、誰か教えてこういうの…。
var v = new UnitValue (100, "pt");
こんな感じで値と単位を引数にして渡します。任意の単位にして値を取り出すことが可能で、
$.writeln(v.as("mm"));
UnitValue.as
メソッドを利用すると、「100pt」として定義した変数v
を、簡単にmm単位に換算できます。
めっちゃ便利じゃん。
単位が入り混じった計算を行うスクリプト
改めて書いてみました。第一引数に文字列として計算式を渡し、第二引数に受け取りたい単位を渡します。
※冒頭のスクリプトを参照してください
単位を付けずに計算式に記述した場合は、第二引数の単位に合わせる仕様です。こんなにスッキリするとは…。
使い方はこんな感じ。
$.writeln(calculateWithUnit("10mm + 1.5pt + 2inch + 3pica + 2.5", "mm")); //76.5291666666667
UnitValueのプロパティとメソッド
プロパティ
プロパティ | 説明 |
---|---|
baseUnit | 計算の基準となる値がUnitValueオブジェクトで入っています。おそらく定数で、0.01388888888889。単位はinch。 |
type | そのUnitValueオブジェクトの単位 |
value | そのUnitValueオブジェクトの値 |
メソッド
メソッド | 引数 | 説明 |
---|---|---|
as | UnitName (文字列) | 単位表記。入っている値をどの単位で換算して取り出すか。 |
convert | UnitName (文字列) | その単位で換算ができるか。できる場合はtrue。できなければエラー(ぇ |
ちなみに、ESTKのオブジェクトモデルビューアで確認する場合は「Core JavaScript Classes」ブラウザにあります。
*1:例えば中綴さんの『小数を含む計算で起こる演算誤差』などがわかりやすいです。