0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【JavaScript】文字列を切り詰めて「...」を付ける

Last updated at Posted at 2022-04-23

目的

画面上に文字列を表示するときに、長すぎる場合は末尾を切り詰めて、さらに続きがあるよということを示すために「...」等を付加したい時があります。substrが使えそうですが、JavaScriptのsubstrはマルチバイト対応してしまっているがために、「あいうえお」でも「abcde」でも同じ5文字とカウントされ、全角のみの場合と半角のみの場合では同じ文字数でも文字列の表示幅が倍近く違うということになります。全角文字は半角文字の倍でカウントして、例えば5文字で切り詰める場合に、「abcde」はそのまま「abcde」、「あいうえお」は「あ...」のように、「...」分を考慮して必要に応じて文字を切り詰め、結果として半角文字分と同程度の幅の文字列を得たいと思います。説明がややこしいですが、要はRubyのtruncateと同じような関数がほしいと思いました。

実装

const truncate = function(string, length, omission = '...') {
    return (string.match(/[^ -~]/g)?.length ?? 0) + string.length <= length ?
           string :
           string.split('')
                 .reduce(
                     (acc, c) => (acc[1] += !c.match(/[ -~]/) + 1) <= length - omission.length ?
                           [acc[0] + c, acc[1]] :
                           [acc[0], length],
                     ['', 0]
                 )[0] + omission;
}

2行目の条件は全角を2半角を1と数えて文字列長が指定の長さを超えているかどうかを判定しています。超えていなければ何もする必要はないのでそのまま返すのが3行目。4行目以降が本体ですが、まずsplitで文字列を文字配列にしてそれをreduceしていきます。アキュムレータとして今までカウントした文字数とそこまでの部分文字列を渡していくので配列になっているのがややダサいところでしょうか。reduce内のmatchは文字毎に全角なら2、半角なら1をアキュムレータに足し込んでいく処理です。ここも2行目で全体にmatchかけてるのに、個々の文字にも同じようなmatchをするのがちょっとなぁ、と思いますが…。あとはまだ指定の長さに達していなければその文字を足し込み、指定の長さを超えるようなら足さない、という判断をしてグルグル回します。reduceの結果の先頭要素が目的の文字列ですから、それに省略したことを表す文字列を付加してtruncateの結果とします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?