Murayama blog.

プログラミング教育なブログ

JavaScript中級トレーニング10問(String編)

この前の記事(JavaScript 30-seconds-of-code String編)をベースにJavaScript問題集を作ってみました。

murayama.hatenablog.com

問題は全部で10問。正規表現をゴリゴリ使うのはなるべく避けてみました。個人的にはヒント見ずに(ググらずに)1時間で全部解けたらマスタークラスだと思います。

  1. isLowerCase
  2. reverseString
  3. truncateString
  4. mapString
  5. mask
  6. compactWhitespace
  7. palindrome
  8. capitalize
  9. byteSize
  10. pluralize

開発環境はブラウザとエディタで十分ですがCodeSandboxも便利です。

codesandbox.io

CodeSandboxをVanillaで起動してもらうとJavaScriptコードの勉強にちょうど良いです。

f:id:yamasahi:20190116085210p:plain

それでははりきってどうぞ。


1 isLowerCase

文字列が小文字か検証します。次の実行結果となるようにisLowerCase関数を定義してください。

isLowerCase('abc'); // true
isLowerCase('a3@$'); // true
isLowerCase('Ab4'); // false

isLowerCase関数を実装して、console.log(isLowerCase('abc')) でtrueが出力されればOKです。

ヒント

String.prototype.toLowerCase()を使って、与えられた文字列を小文字に変換し、元の文字列と等しいか比較します。

const isLowerCase = str => str === str.t__________();

2 reverseString

文字列を反転します。次の実行結果となるようにreverseString関数を定義してください。

reverseString('foobar'); // 'raboof'

ヒント スプレッドオペレータ(...)とArray.prototype.reverse()を使って文字列内の文字の並びを逆順にしString.prototype.join('')によって文字を連結して文字列とします。

const reverseString = str => [...str].r______().j___('');

3 truncateString

指定したサイズで文字列を切り詰めます。次の実行結果となるようにtruncateString関数を定義してください。

truncateString('boomerang', 7); // 'boom...'

ヒント 文字列のサイズの上限を指定します。切り詰められた文字列の後部に'...'を連結して返します。

const truncateString = (str, num) =>
  str.l_____ > num ? str.s____(0, num > 3 ? num - 3 : num) + '...' : str;

4 mapString

文字列に含まれる個々の文字に対して、指定されたコールバック関数を適用して、新たな文字列を生成します。次の実行結果となるようにmapString関数を定義してください。

mapString('lorem ipsum', c => c.toUpperCase()); // 'LOREM IPSUM'

ヒント String.prototype.split('')とArray.prototype.map()を使って、コールバック関数(引数のfn)を文字列内の個々の文字に対して適用します。それからArray.prototype.join('')を使って文字配列を文字列として再結合します。コールバック関数は3つの引数(現在の文字、現在の文字のインデックス、mapString関数の引数に指定された文字列)を受け取ります。

const mapString = (str, fn) =>
  str
    .s____('')
    .m__((c, i) => f_(c, i, str))
    .j___('');

5 mask

文字列を指定されたマスク文字で置き換えます。ただし、文字列の後部については、引数のnumに指定された文字数分はマスクしません。次の実行結果となるようにmask関数を定義してください。

mask(1234567890); // '******7890'
mask(1234567890, 3); // '*******890'
mask(1234567890, -4, '$'); // '$$$$567890'

ヒント String.prototype.slice()を使って、アンマスク(マスクしない)する文字列を取り出し、String.prototype.padStart()で、元の文字列の長さ分のマスク文字を追加します。第2引数のnumが省略された場合、デフォルトで4文字のアンマスク文字を確保します。またnumに負の値が指定された場合は、文字列の先頭部分をアンマスクします。第3引数のmaskが省略された場合、デフォルトのマスク文字に*を使います。

const mask = (cc, num = 4, mask = '*') => `${cc}`.s____(-num).p_______(`${cc}`.l_____, mask);

6 compactWhitespace

連続するホワイトスペース文字(スペース、タブ、改ページ、改行)をホワイトスペース文字1文字に置き換えます。次の実行結果となるようにcompactWhitespace関数を定義してください。

compactWhitespace('Lorem    Ipsum'); // 'Lorem Ipsum'
compactWhitespace('Lorem \n Ipsum'); // 'Lorem Ipsum'

ヒント 正規表現とString.prototype.replace()を使うことで、2文字以上のホワイトスペース文字を1文字に置き換えます。

const compactWhitespace = str => str.r______(/\s{2,}/g, ' ');

7 palindrome

与えられた文字列が回文になっているか検証します。回文の場合、true、そうでない場合、falseを返します。次の実行結果となるようにpalindrome関数を定義してください。

palindrome('taco cat'); // true

ヒント String.prototype.toLowerCase()とString.prototype.replace()を使って非アルファベット文字を除去して小文字に統一し、それからスプレッドオペレータ(...)を使って文字列を文字の配列に変換し、Array.prototype.reverse()、String.prototype.join('')を使って生成した文字列と、元の文字列(非アルファベット文字を除去して小文字に統一したもの)を比較します。

const palindrome = str => {
  const s = str.t__________().r______(/[\W_]/g, '');
  return s === [...s].r______().j___('');
};

8 capitalize

文字列の先頭文字を大文字に変換します。次の実行結果となるようにcapitalize関数を定義してください。

capitalize('fooBar'); // 'FooBar'
capitalize('fooBar', true); // 'Foobar'

ヒント 配列の分割代入とString.prototype.toUpperCase()を使って先頭の文字を大文字にします。 ...restには先頭文字を除く文字の配列が格納されるのでArray.prototype.join('')を使って再び文字列に復元しています。引数のlowerRestが指定されなかった場合は残りの文字列(先頭文字を除く)をそのまま使います。lowerRestにtrueが指定された場合は残りの文字列を小文字に置き換えます。

const capitalize = ([first, ...rest], lowerRest = false) =>
  first.t__________() + (lowerRest ? rest.j___('').t__________() : rest.j___(''));

9 byteSize

文字列の長さをbytesで返します。次の実行結果となるようにbyteSize関数を定義してください。

byteSize('😀'); // 4
byteSize('Hello World'); // 11

ヒント 文字列をBlobオブジェクトに変換してsizeプロパティを参照します。

const byteSize = str => new B___([str]).s___;

10 pluralize

入力された数値によって、基準となる文字列を単数系、あるいは複数形にして返します。第1引数にオブジェクトが指定された場合、関数によって返却されるクロージャを返します。これは"s"による単純な複数形の変換だけでなく、指定されたディクショナリに含まれる複数形単語を返却します。次の実行結果となるようにpluralize関数を定義してください。

pluralize(0, 'apple'); // 'apples'
pluralize(1, 'apple'); // 'apple'
pluralize(2, 'apple'); // 'apples'
pluralize(2, 'person', 'people'); // 'people'

const PLURALS = {
  person: 'people',
  radius: 'radii'
};
const autoPluralize = pluralize(PLURALS);
autoPluralize(2, 'person'); // 'people'

ヒント numが-1か1の場合、単数系の単語を返却します。numがそれ以外の値の場合、複数形の単語を返却します。第3引数のpluralが省略された場合、デフォルトで第2引数のwordに"s"を連結した文字列を複数形の単語として処理するので、必要に応じてカスタマイズすることができます。第1引数のvalがオブジェクトの場合、複数形の単語を格納したディクショナリを保持したクロージャを返却します。

const pluralize = (val, word, plural = word + 's') => {
  const _pluralize = (num, word, plural = word + 's') =>
    [1, -1].i_______(Number(num)) ? word : plural;
  if (typeof val === 'object') return (num, word) => __________(num, word, val[word]);
  return __________(val, word, plural);
};

答え

お疲れ様でした。答えはこちらの記事を参考に。

murayama.hatenablog.com