📝

JavaScript で書式指定フォーマット

2024/03/27に公開

1. はじめに

JavaScriptで、動的に変数を文字列に埋め込む際、テンプレートリテラルが、簡単で良く使われている認識です。

console.log(`v: ${1.5}`); // "v: 1.5";

一方で、書式を指定して値を文字列に変換することがサポートされていないようです。
毎回スクラッチで実装するのは手間なので、(主に自分用に) 実装して公開しました。
(npmの事を良くわかっていないのでパッケージングしていません。今だったらJSRがいいんですかね。)

https://github.com/ymd-h/format-js

2. 使い方

Python の f-string のような書式指定文字列化と、date コマンドのような書式指定文字列化の大きく2つの書式を提供しています。
また、両方にそのまま使えるデフォルトの formatter と、カスタムできる仕組みを用意しています。

2.1 f-string like

疑似シンタックス: {index[:[[align]width][.precision]type]}
単一のメッセージテンプレートに複数の値を差し込む形式

2.1.1 デフォルト

import { format } from "https://cdn.jsdelivr.net/gh/ymd-h/format-js/format.js";

format("{0} + {1} = {2}", 1, 2, 1+2); // "1 + 2 = 3"
format("Precision: {0:.2f}", 1.78); // "Precision: 1.78"
format("Width: {0:4d}", 1); // "Width:   1"
format("Hex: {0:x}", 15); // "Hex: f"
format("Align: {0:<4d}", 1); // "Align: 1   "

2.1.2 パッチによる微修正

新しく、精度情報も表示する w 書式と、余ったスペースに * を詰める * 配置を追加してみた例

import { patch_default_format } from "https://cdn.jsdelivr.net/gh/ymd-h/format-js/format.js";

const f = patch_default_format(
    { // key: (value: *, precision: number) => formatted_string
        "w": (value, precision) => value.toFixed(precision) + ` (${precision})`,
    }, // Patch for Format Handlers (optional)
    { // key: (value: string, width: number) => aligned_string
        "*": (value, width) => value.padStart(width, "*"),
    }, // Patch for Align (optional)
);

f.format("{0:.2w}", 1); // "1.00 (2)"
f.format("{0:.6w}", 1.25); // "1.000000 (6)"
f.format("{0:*6.2f}", 1); // "**1.00"

2.1.3 フルスクラッチ

完全にスクラッチで formatter を構築する例。
省略していますが、 handlers / align に指定できる内容は、2.1.2のパッチと同じです。
その他に、固定浮動小数点のデフォルト精度をオプションで指定できます。

import { FStringLikeFormatter } from "https://cdn.jsdelivr.net/gh/ymd-h/format-js/format.js";

const f = new FStringLikeFormatter(
    {
        ...
    }, // handlers
    {
        ...
    }, // align
    { defaultPrecision: 2 }, // options (optional)
);

f.format("My name is {0}.", "ymd-h");

2.2 date like

% に続けて書式を指定します。
単一のメッセージテンプレートに単一の値 (通常はDate) を差し込む形式。

2.2.1 デフォルト

import { format_date } from "https://cdn.jsdelivr.net/gh/ymd-h/format-js/format.js";

format_date("%Y-%m-%d %H:%M:%S", new Date(2024, 2, 24, 18, 44, 52)); // "2024-03-24 18:44:52"
format_date("%T", new Date(2024, 2, 24, 18, 44, 52)); // "18:44:52"

2.2.2 パッチによる微修正

p の表記を a.m. / p.m. に上書きしてみた例

import { patch_default_formatformat_date } from "https://cdn.jsdelivr.net/gh/ymd-h/format-js/format.js";

const f = patch_default_formatformat_date({
    "p": d => (d.getHours() < 12) ? "a.m." : "p.m.",
});

f.format("%p", new Date(2024, 2, 24, 18, 44, 52)); // "p.m."

2.2.3 フルスクラッチ

完全にスクラッチで作成する例。
この方式であれば、 Date 以外への対応も可能

import { DateLikeFormatter } from "https://cdn.jsdelivr.net/gh/ymd-h/format-js/format.js";

const f = new DateLikeFormatter({
    "p": d => (d.getHours() < 12) ? "a.m." : "p.m.",
});

f.format("%p", new Date(2024, 2, 24, 18, 44, 52)); // "p.m."

3. デフォルト formatter に定義済みの書式・配置

3.1 f-String like

format description
s 文字列 (.toString())
b 2進数
c ユニコード文字 (String.fromCodePoint())
d 整数 (10進数)
o 8進数
x 16進数。a-f を利用
X 16進数。A-F をを利用
e 科学的表記 (指数表記)。基数に e を利用
E 科学的表記 (指数表記)。基数に E を利用
f 固定浮動小数点表記。nan / infinity を利用
F 固定浮動小数点表記。NAN / INFINITY を利用
% パーセント (百分率) 表記。 (100を掛けた固定浮動小数点表記に %)
align description
< 左詰め
^ 真ん中寄せ
> / (empty) 右詰め (default)

3.2 date like

format description
%y 世紀なし年 (2桁)
%Y 年 (4桁)
%m 月 (01 - 12)
%d 日 (01 - 31)
%H 時 (24時間表記) (00 - 23)
%I 時 (12時間表記) (01 - 12)
%p AM or PM
%M 分 (00 - 59)
%S 秒 (00 - 59)
%f ミリ秒 (000 - 999)
%s Unix Time。 1970-01-01 00:00:00 UTC からの経過秒
%T %H:%M:%S と同じ
%w 曜日の数字表記。 日曜が 0。 (0 - 6)
%% % (エスケープ)

4. 実装

実装は、正規表現 (RegExp) を用いて、 String.prototype.replaceAll(pattern, replacement) (MDN) で差し替える実装です。

この2つ目の引数 replacement には関数を指定することができるため、この関数で書式に応じた変換を行っています。

さっと使えるデフォルトとユーザーによるカスタマイズを両立させるために、正規表現を保持するクラスを作り、デフォルトインスタンスを用意すると伴に、パッチによる微修正ができるようにしました。

5. まとめ

JavaScript で書式指定文字列化をする format.js を実装して公開しました。

https://github.com/ymd-h/format-js

もし興味を持ってくれた人がいたら使ってみたり、コードを読んでみたり、レポジトリにスターつけたりしてくれると嬉しいです。

Discussion