バッチファイルで桁数そろえて001,002…099,100って出力したい

「試験用のcsvファイルを作るぞ～」
「ダミーユーザーが200人必要か…user1とかでいいか」
「Excelを使うのも面倒だし、batでちゃちゃっと書いちゃおう」

```bat:bat
for /l %%i in (1,1,200) do echo user%%i>>hoge.csv
```

「これでよし」
「実行して、できたcsvをインポートしてと…」

```:インポート先でユーザー名順表示
user1
user10
user100
user101
user102
︙
user98
user99
```

「順番ぐちゃぐちゃやないかい」

　こんな経験、一度はしたことがあるのではないだろうか。数値が文字列として処理されてしまうが故の事故である。
 というわけで3桁の数値を順番に表示するため、こんな解決策を考えてみた。

# if文を使った例

　何かしらプログラミング経験のある人なら真っ先に思いつきそうなif関数を使った場合分け。
 日ごろCやjavaを使ってる人にとってはbatは少し独特かもしれないので、その辺りを重点的に解説しよう。

 ---

 　と言ってもさほど難しい話ではない。
  001,002…010,011…100,101…というように常に3桁になるように0で調整すれば、文字列順でも上手く表示されるはず。要は1桁のときは頭に0を２つ、2桁なら1つ、3桁ならつけなければよいのだ。
  1桁のとき、2桁のとき、3桁のときと場合分けするならif分の出番だ。

```bat:こんな感じでどうだろう
for /l %%i in (1,1,200) do (
	if %%i leq 99 (
	if %%i leq 9 (
	set Num=00%%i) else (
	set Num=0%%i)) else (
	set Num=%%i)
	echo %Num%>>hoge.csv)

 rem ↓出力結果（これはコメントアウトです）
 rem ECHO は <ON> です。
```

　これが第一の落とし穴である。
 バッチファイルといっても結局はコマンドプロンプトに入力してるだけなので、上の例だと一行ずつ処理されてしまい、変な出力になる。
 もちろん1行で書けばちゃんと読み取ってくれるのだが

 ```bat
 for /l %%i in (1,1,200) do (if %%i leq 99 (if %%i leq 9 (set Num=00%%i) else (set Num=0%%i)) else (set Num=%%i) echo %Num%>>test.csv)

rem 読みづらい…
 ```

 というわけで**遅延環境変数**君の出番である。詳しくはこの辺

 https://qiita.com/tana_tomo_1025/items/7f824a154f004f610386

 を参考にしてほしいのだが、要は``setlocal enabledelayedexpansion`` ``endlocal``で挟めば一括りで処理してくれる。

 ```bat
 setlocal enabledelayedexpansion
 for /l %%i in (1,1,200) do (
	if %%i leq 99 (
	if %%i leq 9 (
	set Num=00%%i) else (
	set Num=0%%i)) else (
	set Num=%%i)
	echo %Num%>>hoge.csv)
 endlocal
 
 rem 何も出力されない…
 ```

 　これも地味にわかりづらいポイントで、実は遅延環境変数はパーセント（%）ではなくエクスクラメーション（!）で囲まなくてはいけないのだ。

というわけでできあがったのがこちら。個々の関数についても後述する。

```bat:例文1
@echo off
chcp 65001
setlocal enabledelayedexpansion
for /l %%i in (1,1,200) do (
	if %%i leq 99 (
	if %%i leq 9 (
	set Num=00%%i) else (
	set Num=0%%i)) else (
	set Num=%%i)
	echo ユーザー!Num!>>hoge.csv)
endlocal
pause
```

<details><summary>関数の解説はこちら</summary>

### 解説

1. `@echo off`
    - コマンドプロンプトでのコマンドの表示をオフにします。

2. `setlocal enabledelayedexpansion`
    - 遅延環境変数の展開を有効にします。これにより、ループ内で変数の値を変更しても即座に反映されるようになります。

3. `chcp 65001`
    - コードページをUTF-8に設定します。これにより、UTF-8エンコーディングの文字を正しく扱うことができます。

4. `for /l %%i in (1,1,200) do ( ... )`
    - 言わずと知れたループ関数
    - 基本構文は``for /l %%変数 in (開始,増分,終了) do (処理)``
    - ``/l``以外のコマンドもある（今回は割愛）
    - 1から200までの数値を使ってループを実行します。`%%i`はループカウンタです。

5. `if %%i leq 99 ( ... )`
    - `%%i`が99以下の場合の条件分岐です。

6. `if %%i leq 9 ( ... )`
    - `%%i`が9以下の場合の条件分岐です。

7. `set Num=00%%i`
    - `%%i`が9以下の場合、`Num`変数に先頭に00を付けた値を設定します（例：`001`, `002`, ...）。

8. `set Num=0%%i`
    - `%%i`が10以上99以下の場合、`Num`変数に先頭に0を付けた値を設定します（例：`010`, `011`, ...）。

9. `set Num=%%i`
    - `%%i`が100以上の場合、`Num`変数にそのままの値を設定します（例：`100`, `101`, ...）。

10. `echo ユーザー!Num!>>hoge.csv`
    - `ユーザー`という文字列に`Num`変数の値を付け加えたものを`hoge.csv`ファイルに追記します（例：`ユーザー001`, `ユーザー002`, ...）。
    - この行を丸ごと``set /P X=ユーザー!Num!,<NUL >>hoge.csv``とすると改行無しで出ます。
    一つのデータにたくさん属性を付けたいときなどに使えそうですね。

11. `endlocal`
    - `setlocal`で設定したローカル環境を終了します。

12. `pause`
    - スクリプトの実行を一時停止し、ユーザーの入力を待ちます。

このスクリプトは、1から200までの数値を持つユーザーIDを生成し、それを`hoge.csv`ファイルに書き込むものです。各ユーザーIDは3桁のゼロパディング形式で出力されます。

</details>


# Substrを使った例

　と言っても実際にコマンドプロンプトにSubstrがあるわけではないのだが…
 要は３桁と決まっているのだから、頭に0を付けたうえで、下から３桁**切り出せば**いいのだ。

 ```bat
 1 → 001 → 001
 10 → 0010 → 010
 100 → 00100 → 100
 rem こんなイメージ
 ```

 　切り出しの構文は ``%変数名:~開始位置,文字数%``
 数字の前にハイフン（-）を置くと反対向きになる。つまり下から切り出したいなら
 
 ```bat:切り出し
 echo %substr:~-3%>>hoge.txt
 rem 最後まで、のときは文字数は指定しなくてもよい
 ```

 　00を頭に付ける、文字列の結合は文字列同士をつなげるだけでよい。

  ```bat:結合
 set str1=hoge
 set str2=fuga
 set substr=%str1%%str2%
 echo substr
 
 rem hogefuga
  ```

  今回もまたfor文でループさせれば完成。

  ```bat:例文2
  @echo off
setlocal enabledelayedexpansion
for /l %%i in (1,1,200) do (
	set str1=00
	set str2=%%i
	set substr=!str1!!str2!
	echo user!substr:~-3!>>hoge.txt)
endlocal
pause
  ```

:::note warn
今回も遅延環境変数は!で囲むのを忘れないように
:::

---

 以上