見出し画像

[SCSS|Sass] 文字列型の数字をちゃんと数値型にしたい(2) 複数桁に対応

前回の続き。一桁の値しか変換できなかったので複数桁の変換に対応させる。

引数で受け取った文字数の分、繰り返し変換する機能を実装する。
話が長くなるので、とりあえず先に完成品を掲載しておく。

自作関数 今回の目標の完成品

@function str2num($val) {
	@if number == type-of($val) {
		@return $val;
	} @else if string != type-of($val) {
		@warn "#{$val} is not string.";
		@return $val;
	}

	$num-map: (
		'0' : 0,
		'1' : 1,
		'2' : 2,
		'3' : 3,
		'4' : 4,
		'5' : 5,
		'6' : 6,
		'7' : 7,
		'8' : 8,
		'9' : 9,
	);

	$num: 0;

	$tmp: 0;

	$length: str-length($val);

	@for $i from 0 to $length {

		$pos: $i;

		$tmp: str-slice($val, $length - $i, $length - $i);

		$tmp: map-get($num-map, $tmp);

		@if not $tmp {
			@warn "'#{$val}' is not string type numbers.";
			$tmp: $val;
		}

		$digit: 1;

		@if 0 < $pos {
			@for $k from 1 through $pos {
				$digit: $digit * 10;
			}

			$tmp: $tmp * $digit;
		}

		$num: $num + $tmp;

	}

	@return $num;
}

解説


変換中に使用する変数を初期化

$num: 0;
$tmp: 0;

$num: 0;
数値型に変換した結果を保存する変数。ゼロで初期化。
最終的にこれをリターンする。

$tmp: 0;
引数で受け取った数字を1文字ずつ取り出して変換するので、これから処理する文字を保存する一時保存用の変数。

受け取った文字数を取得

$length: str-length($val);

1文字ずつ変換の作業を繰り返すため、何文字あるのか調べる。

文字数分繰り返すループ処理

@for $i from 0 to $length {}

for ループはカウントを取りながら {} の中の処理を繰り返す。
ここでは変数 $i でカウントする。
0 から開始して $length(文字数が代入されている)まで。
3文字あれば、 0 から 3 まで 4回繰り返す。3文字なのに4回なの? という疑問は以下のループ内の処理の説明にて。

★ループ内の処理

何桁目か記録する

$pos: $i;

複数桁に対応するため、何桁目を処理してるのか記録しておく。

処理する一文字を取得

$tmp: str-slice($val, $length - $i, $length - $i);

str-slice() は 文字列から指定された区間の文字を取り出す。
@see https://sass-lang.com/documentation/modules/string/#slice

ここでは文字列の末尾から処理するため $length - $i の計算により取得位置を逆順にしている。
3文字を変換する場合
$length - $i :
3 - 0 = 3(3文字目)
3 - 1 = 2(2文字目)
3 - 2 = 1(1文字目)
3 - 3 = 0(0文字目)
ゼロ文字目は存在しないので実質処理されない。

マップから $tmp を検索

// 変更前: $tmp: map-get($num-map, $val);
$tmp: map-get($num-map, $tmp);

前回は引数の $val を直接検索していたが、取り出した1文字を対象に検索するようコードを変更。

桁処理用の変数を初期化

$digit: 1;

桁処理の計算に使う。初期値は 1 で、ループ毎に初期化される。

十の位からの分岐処理

@if 0 < $pos {}

一の位以上は桁処理が必要になる。
$pos が 0 のときは一の位、 1 のときは十の位を処理しているので、0 より大きいときに実行する分岐を追加。

桁処理

@for $k from 1 through $pos {
	$digit: $digit * 10;
}

ループ内に2個目のループ。
$digit * 10 で桁を上げる計算。十の位なら1回、百の位なら2回繰り返す。

1個目のループと同じ @for だが「$k from 1 through $pos 」になっている。
"through" と "to" はカウントの最後にループ処理をするかどうかが違う。

through はループ回数に含まない。 to はループ回数に含む。
カウントが目的の値に至ったとき
$tmp: $tmp * $digit;

10 や 100 といった桁が求められたら、取り出していた1桁と掛ける。
十の位の値は 10~90 または 0 になる。

$num: $num + $tmp;

$num を合計として、各桁で求めた値を加算していく。

$num をリターン

// 変更前: @return $tmp;
@return $num;

前回は $tmp をマップの検索結果にしていたが、今回は $num に変換結果が保存されている。

これで以下のような結果が得られる。

$val: "123450";
$val:str2num($val);
@debug "#{$val} #{type-of($val)}";

> Debug: 123450 number


この記事が気に入ったらサポートをしてみませんか?