JavaScriptで言語処理100本ノック(第1章)

出典：http://www.cl.ecei.tohoku.ac.jp/nlp100/

#####00. 文字列の逆順
>文字列”stressed"の文字を逆に（末尾から先頭に向かって）並べた文字列を得よ．

```javascript
[...'stressed'].reverse().join``;
```

#####01. 「パタトクカシーー」
>「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ．

```javascript
[...'パタトクカシーー'].filter((v, i) => !(i % 2)).join``;
```

#####02. 「パトカー」＋「タクシー」＝「パタトクカシーー」
>「パトカー」＋「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ．

```javascript
[...'パトカー'].map((v, i) => v + 'タクシー'[i]).join``;
```

#####03. 円周率
>"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し，各単語の（アルファベットの）文字数を先頭から出現順に並べたリストを作成せよ．

```javascript
'Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.'
  .replace(/[,.]/g,'')
  .split(/\s/)
  .map(v => v.length);
```

#####04. 元素記号
>“Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し，1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字，それ以外の単語は先頭に2文字を取り出し，取り出した文字列から単語の位置（先頭から何番目の単語か）への連想配列（辞書型もしくはマップ型）を作成せよ．

```javascript
new Map('Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.'
  .split(/\s/)
  .map((v, i) => [String(i).match(/^[045678]$|14|15|18/) ? v[0] : v[0] + v[1], i])
);
```

#####05. n-gram
>与えられたシーケンス（文字列やリストなど）からn-gramを作る関数を作成せよ．この関数を用い，"I am an NLPer"という文から単語bi-gram，文字bi-gramを得よ．

```javascript
const nGram = (arr, n) => [...Array(arr.length - n + 1).keys()]
  .map((v, i) => arr.slice(i, i + n));
nGram('I am an NLPer'.split(/\s/), 2);
nGram('I am an NLPer', 2);
```

#####06. 集合
>“paraparaparadise"と”paragraph"に含まれる文字bi-gramの集合を，それぞれ, XとYとして求め，XとYの和集合，積集合，差集合を求めよ．さらに，’se'というbi-gramがXおよびYに含まれるかどうかを調べよ．

```javascript
const nGram = (arr, n) => [...Array(arr.length - n + 1).keys()]
  .map((v, i) => arr.slice(i, i + n));
const X = [...new Set(nGram('paraparaparadise', 2))];
const Y = [...new Set(nGram('paragraph', 2))];
console.log(`和集合：${[...new Set([...X, ...Y])]}`);
console.log(`積集合：${X.filter(v => Y.includes(v))}`);
console.log(`差集合：${X.filter(v => !(Y.includes(v)))}`);
console.log(`seがXに含まれる：${X.includes('se')}`);
console.log(`seがYに含まれる：${Y.includes('se')}`);
```

#####07. テンプレートによる文生成
>引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ．さらに，x=12, y="気温", z=22.4として，実行結果を確認せよ．

```javascript
const e = (x, y, z) => `${x}時の${y}は${z}`;
console.log(e(12, '気温', 22.4));
```

#####08. 暗号文
>与えられた文字列の各文字を，以下の仕様で変換する関数cipherを実装せよ．
- 英小文字ならば(219 - 文字コード)の文字に置換
- その他の文字はそのまま出力
この関数を用い，英語のメッセージを暗号化・復号化せよ．

```javascript
const cipher = str => str
  .replace(/[a-z]/g, m => String.fromCharCode(219 - m.charCodeAt()));
console.log(cipher('Hello こんにちは'));
console.log(cipher(cipher('Hello こんにちは')));
```

#####09. Typoglycemia
>スペースで区切られた単語列に対して，各単語の先頭と末尾の文字は残し，それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ．ただし，長さが４以下の単語は並び替えないこととする．適当な英語の文（例えば"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."）を与え，その実行結果を確認せよ．

```javascript
const shuffle = arr => arr
  .map(v => [Math.random(), v])
  .sort(([a], [b]) => a - b)
  .map(v => v[1]);
const func = str => str
  .split(/\s/)
  .map(v => v.length <= 4 ? v : [v[0], ...shuffle([...v.slice(1, -1)]), v.slice(-1)].join``)
  .join` `;
console.log(func(`I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .`));
```