diff --git a/CHANGELOG.md b/CHANGELOG.md index 17d265ab..fd30b69a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - `Date:year`系の関数に0を渡すと現在時刻になる問題を修正 - シンタックスエラーなどの位置情報を修正 - `arr.reduce`が空配列に対して初期値なしで呼び出された時、正式にエラーを出すよう +- `str.pad_start`,`str.pad_end`を追加 # 0.18.0 - `Core:abort`でプログラムを緊急停止できるように diff --git a/docs/primitive-props.md b/docs/primitive-props.md index 1356e1c3..8a51bece 100644 --- a/docs/primitive-props.md +++ b/docs/primitive-props.md @@ -78,6 +78,16 @@ _fromIndex_が指定されていれば、その位置から検索を開始しま _fromIndex_が負値の時は末尾からの位置(文字列の長さ+_fromIndex_)が使用されます。 該当が無ければ-1を返します。 +### @(_v_: str).pad_start(_width_: num, _pad_?: str): str +文字列の長さがが _width_ になるように、先頭を _pad_ の繰り返しで埋めた新しい文字列を返します。\ +_pad_ を省略した場合、空白`' '`で埋められます。\ +_pad_ が長すぎる場合、_pad_ の末尾が切り捨てられます。 + +### @(_v_: str).pad_end(_width_: num, _pad_?: str): str +文字列の長さがが _width_ になるように、末尾を _pad_ の繰り返しで埋めた新しい文字列を返します。\ +_pad_ を省略した場合、空白`' '`で埋められます。\ +_pad_ が長すぎる場合、_pad_ の末尾が切り捨てられます。 + ### @(_v_: str).trim(): str 文字列の前後の空白を取り除いたものを返します。 diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts index f158546c..9fcbb3ad 100644 --- a/src/interpreter/primitive-props.ts +++ b/src/interpreter/primitive-props.ts @@ -119,6 +119,20 @@ const PRIMITIVE_PROPS: { const res = target.value.codePointAt(i.value) ?? target.value.charCodeAt(i.value); return Number.isNaN(res) ? NULL : NUM(res); }), + + pad_start: (target: VStr): VFn => FN_NATIVE(([width, pad], _) => { + assertNumber(width); + const s = (pad) ? (assertString(pad), pad.value) : ' '; + + return STR(target.value.padStart(width.value, s)); + }), + + pad_end: (target: VStr): VFn => FN_NATIVE(([width, pad], _) => { + assertNumber(width); + const s = (pad) ? (assertString(pad), pad.value) : ' '; + + return STR(target.value.padEnd(width.value, s)); + }), }, arr: { diff --git a/test/index.ts b/test/index.ts index bfb716a4..f67ccc99 100644 --- a/test/index.ts +++ b/test/index.ts @@ -2627,6 +2627,38 @@ describe('primitive props', () => { ARR([NUM(97), NUM(98), NUM(99), NUM(240), NUM(169), NUM(184), NUM(189), NUM(240), NUM(159), NUM(145), NUM(137), NUM(240), NUM(159), NUM(143), NUM(191), NUM(240), NUM(159), NUM(145), NUM(168), NUM(226), NUM(128), NUM(141), NUM(240), NUM(159), NUM(145), NUM(166), NUM(100), NUM(101), NUM(102)]) ); }); + + test.concurrent("pad_start", async () => { + const res = await exe(` + let str = "abc" + <: [ + str.pad_start(0), str.pad_start(1), str.pad_start(2), str.pad_start(3), str.pad_start(4), str.pad_start(5), + str.pad_start(0, "0"), str.pad_start(1, "0"), str.pad_start(2, "0"), str.pad_start(3, "0"), str.pad_start(4, "0"), str.pad_start(5, "0"), + str.pad_start(0, "01"), str.pad_start(1, "01"), str.pad_start(2, "01"), str.pad_start(3, "01"), str.pad_start(4, "01"), str.pad_start(5, "01"), + ] + `); + eq(res, ARR([ + STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR(" abc"), STR(" abc"), + STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("0abc"), STR("00abc"), + STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("0abc"), STR("01abc"), + ])); + }); + + test.concurrent("pad_end", async () => { + const res = await exe(` + let str = "abc" + <: [ + str.pad_end(0), str.pad_end(1), str.pad_end(2), str.pad_end(3), str.pad_end(4), str.pad_end(5), + str.pad_end(0, "0"), str.pad_end(1, "0"), str.pad_end(2, "0"), str.pad_end(3, "0"), str.pad_end(4, "0"), str.pad_end(5, "0"), + str.pad_end(0, "01"), str.pad_end(1, "01"), str.pad_end(2, "01"), str.pad_end(3, "01"), str.pad_end(4, "01"), str.pad_end(5, "01"), + ] + `); + eq(res, ARR([ + STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("abc "), STR("abc "), + STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("abc0"), STR("abc00"), + STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("abc0"), STR("abc01"), + ])); + }); }); describe('arr', () => {