できない.dev

数値をゼロ埋めするには

42 を 00042 のように、決めた桁数に足りない分を先頭のゼロで埋めた文字列にする基本形を各言語で示す。
負の数で符号の前にゼロが入る罠と、桁数に符号を数えるかどうかの言語差、桁があふれたときの挙動までを扱う。

公開:

各言語見出しの横のバッジは検証状態を表す。実行確認済みはコードを実際に実行して確認したもの、静的確認は構文と公式 API ドキュメントで確認したものである。

Python 実行確認済み

n = 42
print(f"{n:05}")            # 00042
print(str(n).zfill(5))      # 00042
print(f"{-42:05}")          # -0042(符号も幅 5 に数える)
print("-42".zfill(5))       # -0042
print(f"{3.5:06.2f}")       # 003.50(小数点と小数部も幅に入る)
print(f"{123456:05}")       # 123456(桁が多いときは切り詰めない)
 
# 連番のファイル名を作る("img_" + n のように数値を + でつなぐと TypeError)
for i in (1, 12, 123):
    print("img_" + f"{i:03}" + ".png")  # img_001.png / img_012.png / img_123.png

f-string の書式指定 05 は、幅 5 に足りない分を先頭のゼロで埋める。
文字列になっている値は str.zfill でも埋められ、どちらも符号を幅に数えたうえで符号の後ろにゼロを入れるので、-42 は -0042 になる。
連番のファイル名を作るときに "img_" + i のように数値を + でつなぐと TypeError になるため、書式指定で文字列にしてからつなぐ。

うまくいかない時: Python で「TypeError: can only concatenate str (not "int") to str」が直らない

JavaScript 実行確認済み

const n = 42;
console.log(String(n).padStart(5, "0"));   // 00042
console.log(String(-42).padStart(5, "0")); // 00-42(符号の前にゼロが入る)
console.log(String(123456).padStart(5, "0")); // 123456(切り詰めない)
 
// 負の数は符号を外してから埋める
const zeroPad = (v, width) =>
  v < 0 ? "-" + String(-v).padStart(width - 1, "0") : String(v).padStart(width, "0");
console.log(zeroPad(-42, 5)); // -0042
 
// Intl.NumberFormat の minimumIntegerDigits でも埋められる
const fmt = new Intl.NumberFormat("en-US", { minimumIntegerDigits: 5, useGrouping: false });
console.log(fmt.format(42));  // 00042
console.log(fmt.format(-42)); // -00042(符号は桁数に数えない)

padStart は文字列のメソッドなので、数値は String で文字列にしてから呼ぶ。
padStart は符号を区別せず先頭に文字を足すだけで、-42 は 00-42 になるため、負の数を扱うなら符号を外して埋めてから付け直す。
Intl.NumberFormat の minimumIntegerDigits でも埋められるが、こちらは符号を桁数に数えないので -42 は -00042 になる。

TypeScript 実行確認済み

// 数値に padStart は無いので、先に文字列にする
function zeroPad(value: number, width: number): string {
  if (!Number.isInteger(value)) {
    throw new RangeError(`整数ではない: ${value}`);
  }
  const digits = String(Math.abs(value)).padStart(value < 0 ? width - 1 : width, "0");
  return value < 0 ? `-${digits}` : digits;
}
 
console.log(zeroPad(42, 5));  // 00042
console.log(zeroPad(-42, 5)); // -0042
console.log(zeroPad(7, 2));   // 07
 
// 日付の月日を 2 桁にする定番の使い方
const d = new Date(2026, 0, 5); // 月は 0 始まり
const ymd = `${d.getFullYear()}-${zeroPad(d.getMonth() + 1, 2)}-${zeroPad(d.getDate(), 2)}`;
console.log(ymd); // 2026-01-05

number 型には padStart が無く、n.padStart(5, "0") と書くと TS2339(Property 'padStart' does not exist on type 'number')になるので、String で文字列にしてから呼ぶ。
小数を渡すと 3.5 が 003.5 のように中途半端に埋まるため、整数だけを受け付ける関数にしておくと呼び出し側の誤りに気付ける。

うまくいかない時: TypeScript で「Property does not exist on type」が解消できない

Go 実行確認済み

package main
 
import (
	"fmt"
	"strconv"
	"strings"
)
 
func main() {
	fmt.Printf("%05d\n", 42)     // 00042
	fmt.Printf("%05d\n", -42)    // -0042(符号も幅 5 に数える)
	fmt.Printf("%06.2f\n", 3.5)  // 003.50
	fmt.Printf("%05d\n", 123456) // 123456(切り詰めない)
 
	// 幅を変数で渡すときは * を使う
	width := 8
	s := fmt.Sprintf("%0*d", width, 42)
	fmt.Println(s) // 00000042
 
	// strings.Repeat で自前に埋めると、負の数で符号の前にゼロが入る
	t := strconv.Itoa(-42)
	fmt.Println(strings.Repeat("0", 5-len(t)) + t) // 00-42
}

fmt の書式指定 %05d は、幅 5 に足りない分を符号の後ろのゼロで埋める。
幅を実行時に決めるときは %0*d と書き、幅を引数で渡す。
strings.Repeat で自前に足す書き方は符号を区別しないので、負の数では 00-42 のように崩れる。

Rust 実行確認済み

fn main() {
    println!("{:05}", 42);      // 00042
    println!("{:05}", -42);     // -0042(符号も幅 5 に数える)
    println!("{:06.2}", 3.5);   // 003.50
    println!("{:05}", 123456);  // 123456(切り詰めない)
 
    // 幅を変数で渡すときは width$ を使う
    let width = 8;
    let s = format!("{:0width$}", 42, width = width);
    println!("{}", s); // 00000042
 
    // 文字列の右寄せ {:0>5} は符号を区別しない
    println!("{:0>5}", (-42).to_string()); // 00-42
}

書式指定 {:05} は、幅 5 に足りない分を符号の後ろのゼロで埋める。
幅を変数で決めるときは {:0width$} と書き、名前付き引数で幅を渡す。
{:0>5} は「0 で右寄せ」という文字列の書式なので、数値を文字列にしてから使うと符号の前にゼロが入る。

Java 実行確認済み

import java.util.Locale;
 
public class ZeroPad {
    public static void main(String[] args) {
        System.out.println(String.format("%05d", 42));                 // 00042
        System.out.println(String.format("%05d", -42));                // -0042(符号も幅 5 に数える)
        System.out.println(String.format(Locale.ROOT, "%06.2f", 3.5)); // 003.50
        System.out.println(String.format("%05d", 123456));             // 123456(切り詰めない)
 
        // 幅を変数で渡すときは書式文字列を組み立てる
        int width = 8;
        System.out.println(String.format("%0" + width + "d", 42)); // 00000042
 
        // %05s のように文字列に 0 フラグを付けると例外になる
        try {
            System.out.println(String.format("%05s", "42"));
        } catch (java.util.FormatFlagsConversionMismatchException e) {
            System.out.println(e.getClass().getSimpleName()); // FormatFlagsConversionMismatchException
        }
    }
}

String.format の %05d は、幅 5 に足りない分を符号の後ろのゼロで埋める。
0 フラグは数値の変換にしか使えず、%05s のように文字列に付けると FormatFlagsConversionMismatchException が投げられる。
小数の %f は既定ロケールの小数点を使うため、Locale.ROOT などを明示して出力を固定する。

C# 実行確認済み

using System.Globalization;
 
int n = 42;
Console.WriteLine(n.ToString("D5"));      // 00042
Console.WriteLine(n.ToString("00000"));   // 00042
Console.WriteLine((-42).ToString("D5"));  // -00042(D5 は符号を除いた桁数)
Console.WriteLine(123456.ToString("D5")); // 123456(切り詰めない)
Console.WriteLine(3.5.ToString("000.00", CultureInfo.InvariantCulture)); // 003.50
 
// 文字列補間でも同じ書式指定子が使える
Console.WriteLine($"img_{7:D3}.png"); // img_007.png
 
// PadLeft は文字列として埋めるので、負の数では符号の前にゼロが入る
Console.WriteLine((-42).ToString().PadLeft(5, '0')); // 00-42

書式指定子 D5 とカスタム書式 00000 は、どちらも 42 を 00042 にする。
D5 の 5 は符号を除いた数字の桁数を表すので、-42 は -0042 ではなく -00042 になる。
PadLeft は文字列として左を埋めるだけなので、負の数には使わない。

つまずき

文字列として左を埋める関数(JavaScript の padStart、C# の PadLeft、Rust の {:0>5})は符号を区別しないので、-42 を幅 5 で埋めると 00-42 になる。
数値の書式指定(Python の 05、Go と Java の %05d、Rust の {:05})は符号の後ろにゼロを入れて -0042 にする。
負の数が入りうる値を埋めるときは、数値の書式指定を使うか、符号を外して埋めてから付け直す(7 言語とも実行して確認した)。

符号を桁数に数えるかは言語で違う

Python・Go・Rust・Java の幅指定は符号を含めた全体の文字数なので、幅 5 の -42 は -0042 の 5 文字になる。
一方で C# の D5 と JavaScript の Intl.NumberFormat の minimumIntegerDigits は数字だけの桁数を指定するため、-42 は -00042 の 6 文字になる。
固定長のファイル形式やログのように文字数をそろえたい場面では、この違いで列がずれる。

桁があふれても切り詰めない

どの言語の書き方も、値の桁数が指定した幅より多いときは何もしないので、幅 5 で 123456 を埋めると 123456 のまま 6 文字で出る。
ゼロ埋めは桁数の上限ではないため、伝票番号のように桁数を厳密に決めたい場合は、埋める前に値の範囲を確かめる。

この記事は役立ちましたか?