タイポグリセミア現象を用いて、タイポしても気づかれない文章を作りたい


# 概要

### タイポグリセミア現象とは

タイポグリセミア（Typoglycemia）は、文章中のいくつかの単語で最初と最後の文字以外の順番が入れ替わっても正しく読めてしまう現象である。（[Wikipediaより引用](https://ja.wikipedia.org/wiki/%E3%82%BF%E3%82%A4%E3%83%9D%E3%82%B0%E3%83%AA%E3%82%BB%E3%83%9F%E3%82%A2#:~:text=%E3%82%BF%E3%82%A4%E3%83%9D%E3%82%B0%E3%83%AA%E3%82%BB%E3%83%9F%E3%82%A2%EF%BC%88Typoglycemia%EF%BC%89%E3%81%AF%E3%80%81%E6%96%87%E7%AB%A0,%E3%82%8F%E3%82%8C%E3%81%9F%E3%81%93%E3%81%A8%E3%81%AF%E3%81%AA%E3%81%84%E3%80%82)）

### kuromoji.jsとは

kuromoji.jsは、日本語を形態素解析できるJavascriptのプラグインです。
日本語文章を形態素と呼ばれる単語に分割することができます。

下記がGithubのリンクです。

https://github.com/takuyaa/kuromoji.js/


### 今回やりたいこと

今回は、タセイグミポリアとkomjuroi.jsを用いて、
文章を形解態素析しタプイミスした文章を作りたいと思います。

タイセポグミリア現象を使用するので、間違っていても気つがかない文構章成で作ることができます。

<details><summary>気が付きましたか？</summary>

上記説明は、タイセポグミリア現象を用いて文章を作成しました。
改めて、正しい文章です。

> 今回は、タイポグリセミアとkuromoji.jsを用いて、
> 文章を形態素解析しタイプミスした文章を作りたいと思います。
>
> タイポグリセミア現象を使用するので、間違っていても気がつかない文章構成で作ることができます。

</details>

# プログラム

下記が実際のコードとなります。
ブラウザで動作することを想定しています。
kuromoji.jsを読み込む必要があります。

```javascript
kuromoji.builder({ dicPath: "node_modules/kuromoji/dict/" }).build(function (err, tokenizer) {
    if(err) {
        console.log(err);
        return;
    }

    var str = "こんにちは、今日の天気予報によるとサイクロンらしいですよ！";

    // 形態素解析
    var tokens = tokenizer.tokenize( str );
    var result = "";

    for (var i=0;  i < tokens.length; i++){
        var ward = replacingChara(tokens[i].surface_form);

        if (ward === tokens[i].surface_form) {
            result = result + ward;
        } else {
            result = result + "<span class='typo'>" + ward + "</span>";
        }
    }
    //結果を出力
    console.log(result);
});

function replacingChara(str){
    return String(str).replace(/^(.)(.*?)(.)$/, function(v,p1,p2,p3){
        return p1 + sort_random(p2.split('')).join('') + p3;
    });
}


```


# プログラム解説

### 形態素解析した結果

形態素解析した内容は、tokensに入ります。

```js
var tokens = tokenizer.tokenize( str );
```

tokensの中身は、以下のようになります。（長いので折りたたんでいます）
kuromoji.jsで形態素解析すると、文章を切り分けるだけではなく、
「文節の種類」や「カタカナ」や「文章の位置」などを持っていることがわかります。

<details><summary>tokensの中身</summary>

```json
[
    {
        "word_id": 34000,
        "word_type": "KNOWN",
        "word_position": 1,
        "surface_form": "こんにちは",
        "pos": "感動詞",
        "pos_detail_1": "*",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "こんにちは",
        "reading": "コンニチハ",
        "pronunciation": "コンニチワ"
    },
    {
        "word_id": 90910,
        "word_type": "KNOWN",
        "word_position": 6,
        "surface_form": "、",
        "pos": "記号",
        "pos_detail_1": "読点",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "、",
        "reading": "、",
        "pronunciation": "、"
    },
    {
        "word_id": 126270,
        "word_type": "KNOWN",
        "word_position": 7,
        "surface_form": "今日",
        "pos": "名詞",
        "pos_detail_1": "副詞可能",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "今日",
        "reading": "キョウ",
        "pronunciation": "キョー"
    },
    {
        "word_id": 93100,
        "word_type": "KNOWN",
        "word_position": 9,
        "surface_form": "の",
        "pos": "助詞",
        "pos_detail_1": "連体化",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "の",
        "reading": "ノ",
        "pronunciation": "ノ"
    },
    {
        "word_id": 2372920,
        "word_type": "KNOWN",
        "word_position": 10,
        "surface_form": "天気",
        "pos": "名詞",
        "pos_detail_1": "一般",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "天気",
        "reading": "テンキ",
        "pronunciation": "テンキ"
    },
    {
        "word_id": 846450,
        "word_type": "KNOWN",
        "word_position": 12,
        "surface_form": "予報",
        "pos": "名詞",
        "pos_detail_1": "サ変接続",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "予報",
        "reading": "ヨホウ",
        "pronunciation": "ヨホー"
    },
    {
        "word_id": 92030,
        "word_type": "KNOWN",
        "word_position": 14,
        "surface_form": "に",
        "pos": "助詞",
        "pos_detail_1": "格助詞",
        "pos_detail_2": "一般",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "に",
        "reading": "ニ",
        "pronunciation": "ニ"
    },
    {
        "word_id": 2557790,
        "word_type": "KNOWN",
        "word_position": 15,
        "surface_form": "よる",
        "pos": "動詞",
        "pos_detail_1": "自立",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "五段・ラ行",
        "conjugated_form": "基本形",
        "basic_form": "よる",
        "reading": "ヨル",
        "pronunciation": "ヨル"
    },
    {
        "word_id": 92550,
        "word_type": "KNOWN",
        "word_position": 17,
        "surface_form": "と",
        "pos": "助詞",
        "pos_detail_1": "接続助詞",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "と",
        "reading": "ト",
        "pronunciation": "ト"
    },
    {
        "word_id": 717920,
        "word_type": "KNOWN",
        "word_position": 18,
        "surface_form": "サイクロン",
        "pos": "名詞",
        "pos_detail_1": "一般",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "サイクロン",
        "reading": "サイクロン",
        "pronunciation": "サイクロン"
    },
    {
        "word_id": 24150,
        "word_type": "KNOWN",
        "word_position": 23,
        "surface_form": "らしい",
        "pos": "助動詞",
        "pos_detail_1": "*",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "形容詞・イ段",
        "conjugated_form": "基本形",
        "basic_form": "らしい",
        "reading": "ラシイ",
        "pronunciation": "ラシイ"
    },
    {
        "word_id": 23760,
        "word_type": "KNOWN",
        "word_position": 26,
        "surface_form": "です",
        "pos": "助動詞",
        "pos_detail_1": "*",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "特殊・デス",
        "conjugated_form": "基本形",
        "basic_form": "です",
        "reading": "デス",
        "pronunciation": "デス"
    },
    {
        "word_id": 92300,
        "word_type": "KNOWN",
        "word_position": 28,
        "surface_form": "よ",
        "pos": "助詞",
        "pos_detail_1": "終助詞",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "よ",
        "reading": "ヨ",
        "pronunciation": "ヨ"
    },
    {
        "word_id": 91640,
        "word_type": "KNOWN",
        "word_position": 29,
        "surface_form": "！",
        "pos": "記号",
        "pos_detail_1": "一般",
        "pos_detail_2": "*",
        "pos_detail_3": "*",
        "conjugated_type": "*",
        "conjugated_form": "*",
        "basic_form": "！",
        "reading": "！",
        "pronunciation": "！"
    }
]
```
</details>

### タイポグリセミアを実現

正規表現を使いタイポグリセミアを実現しています。
`replacingChara()`は先頭文字と末尾文字以外をランダムに入れ替えて結果を返します。

```javascript
function replacingChara(str){
    return String(str).replace(/^(.)(.*?)(.)$/, function(v,p1,p2,p3){
        return p1 + sort_random(p2.split('')).join('') + p3;
    });
} 
```

### マーキングする

「変換前の文字」と「変換後の文字」が違った場合に
テキストをマーキングできるように、`<span class='typo'></span>`を挿入しています。
class='typo'に対し、スタイルを付与することで変換箇所を確認できるようにするためです。

```javascript
if (ward === tokens[i].surface_form) {
    result = result + ward;
} else {
    result = result + "<span class='typo'>"　+ ward + "</span>";　
}
```


# 実行結果

「こんにちは」と「サイクロン」が変換されています。

```diff
# 元の文章
- こんにちは、今日の天気予報によるとサイクロンらしいですよ！

# 変換後の文章
+ こんちには、今日の天気予報によるとサロイクンらしいですよ！
```


そして、実際に出力されたhtmlです。

```html
<span class='typo'>こんちには</span>、今日の天気予報によると<span class='typo'>サロイクン</span>らしいですよ！
```

ブラウザに表示すると以下のようになります。

|スタイリング|表示|
|-|-|
|スタイリングなし|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/6ade10e8-12b1-3103-84c7-b068c9a6bfed.png)|
|スタイリングあり|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/1278d551-7202-3b02-16fb-c325c9ceee8c.png)|


# まとめ

文章を形態素解析しタイプミスした文章を作ることができました。
そして、日本語には3文字以上の単語が少ないことに気が付きました。
そのため、名詞が連続する場合は、結合して処理したほうが良いかもしれません。

上記の内容を使用したツールを公開しています。ぜひ遊んでみてください。

https://suisui.fun/make_typo/

ここまで読んでいただきあとがりうございました。