8
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 5 years have passed since last update.

「しらける」を「ホワイトキック」に自動変換したかったストーリー

Last updated at Posted at 2019-06-19

リスペクト

「赤の他人」の対義語は「白い恋人」 これを自動生成したい物語
https://qiita.com/youwht/items/f21325ff62603e8664e6

モチベ

チョベリバあたりで同じように流行った(?)オヤジギャグっぽい「ホワイトキック」は結構好きでした.
自動変換はリスペクト先の人のものより簡単にできそうだけど,そのアルゴリズムを使って
ありえない -> 蟻 得ない -> アントノットゲット
かわいい -> 川 良い -> リバーグッド

...
ん?面白くないかも...

まぁやってみっか

実装

環境,使ったもの

node v12.3.1
axios v0.19.0

漢字変換
https://www.google.co.jp/ime/cgiapi.html
漢字検出参考URL
https://pisuke-code.com/js-check-hira-kana-kanzi/
英語翻訳
https://cloud.google.com/translate
英語カタカナ変換
https://www.sljfaq.org/cgi/e2k_ja.cgi

カンマで区切る

ただの英語翻訳するのではなく,意図しない箇所で区切って変換していきます.
次の工程の漢字変換のためにカンマを挿入するだけです.

ex
「おもしろい」

「おも,しろい」

区切ったあとに一文字になってしまうと意味が通じづらくなってしまうので,最低2文字以上としました.
今回,区切る箇所はランダムにしています...

漢字変換

googleのimeの機能が使えるapiがあったのでそれを利用します.
変換後,候補が漢字以外も出てくるので,漢字のみを抽出します.
そこから最終的な二文字をやはりランダムで抽出します.
ここらへんもうまく選びたい...

ex
[["おも",["主","面","オモ","おも","重"]],["しろい",["白い","しろい","白井","城井","シロイ"]]]

[["おも",["主","面","重"]],["しろい",["白い","白井","城井"]]]

["面","白い"]

英語変換

googleの翻訳apiを利用しました

ex
["面","白い"]

["Face","White"]

カタカナ変換

上記のサイトからcgiを利用させていただいております.
最後にかっこよく「・」で挟んで完成です

ex
["Face","White"]

["フェース","ワイト"]

フェース・ワイト

サンプルコード

モジュールとして作成しました.
なので以下のコードだけでは動かず,コマンドラインや,ローカルサーバ,LINEのBOTとして動かすものがgithubにアップロードされているのでそちらを御覧ください.
https://github.com/tkyko13/WhiteKicker

wker.js
"use strict";

const axios = require("axios");

// google translate api
const TRANSLATE_API_KEY = "YOUR_KEY";

// GET通信先
const baseURL = "http://www.google.com/transliterate";
const traBaseURL = "https://translation.googleapis.com/language/translate/v2";
const e2kBaseURL = "https://www.sljfaq.org/cgi/e2k.cgi";

// 与えられた文字列に最低2文字以下でカンマ区切りするパターンを全て返す
// ex こんにちは -> ['こん,にちは', 'こんに,ちは']
// 現在ランダム
function spliceComma(text) {
  // 4文字未満場合はそのまま返す
  if (text.length < 4) {
    return text;
  }
  let retArr = [];
  // for (let i = 2; i < text.length - 1; i++) {
  //   retArr.push(text.slice(0, i) + "," + text.slice(i));
  // }
  // 現在ランダムで一つだけ
  let i = Math.floor(Math.random() * (text.length - 3) + 2);
  retArr.push(text.slice(0, i) + "," + text.slice(i));
  return retArr;
}

// 文字列に漢字が含まれているかの判定
// https://pisuke-code.com/js-check-hira-kana-kanzi/
// 全大文字英語も入っているらしい...
function judgeKanji(text) {
  let regexp = /([\u{3005}\u{3007}\u{303b}\u{3400}-\u{9FFF}\u{F900}-\u{FAFF}\u{20000}-\u{2FFFF}][\u{E0100}-\u{E01EF}\u{FE00}-\u{FE02}]?)/mu;
  return regexp.test(text);
}

// かなから漢字取得,配列で返す
// googleAPIでは漢字以外も返ってくるが,第二引数をtrueにすることで漢字のみ返す
async function getKanjis(kana, kanjiOnly) {
  const res = await axios.get(baseURL, {
    method: "json",
    params: {
      langpair: "ja-Hira|ja",
      text: kana
    }
  });
  if (res && res.data) {
    if (kanjiOnly == true) {
      for (let i = 0; i < res.data.length; i++) {
        for (let j = 0; j < res.data[i][1].length; j++) {
          if (judgeKanji(res.data[i][1][j]) == false) {
            res.data[i][1].splice(j, 1);
          }
        }
      }
      return res.data;
    } else {
      return res.data;
    }
  } else {
    return null; //error
  }
}

// 英語変換
async function getEnglish(word) {
  const res = await axios.get(traBaseURL, {
    method: "post",
    params: {
      q: word,
      target: "en",
      key: TRANSLATE_API_KEY
    }
  });
  return res.data.data.translations[0].translatedText;
}

// 英語からカタカナに変換
async function getKatakana(en) {
  const e2kRes = await axios.get(e2kBaseURL, {
    method: "get",
    params: {
      o: "json",
      lang: "ja",
      word: en
    }
  });
  let ret = "";
  for (let i = 0; i < e2kRes.data.words.length; i++) {
    ret += e2kRes.data.words[i].j_pron_only;
  }
  return ret;
}


/*
 main関数
*/
async function main(text) {
  // console.log(text);

  // カンマ区切りのパターン取得
  let cammaArr = spliceComma(text);
  console.log(cammaArr);

  // 現在はカンマ区切り位置はランダムなので,1パターンだけ漢字取得
  const kanjiArr = await getKanjis(cammaArr[0], true);
  console.log(kanjiArr);

  // 一旦漢字の段階でランダムで最終表示のワードを決めちゃう
  let kanjiDecArr = [];
  for (let i = 0; i < kanjiArr.length; i++) {
    let ind = Math.floor(Math.random() * kanjiArr[i][1].length);
    kanjiDecArr.push(kanjiArr[i][1][ind]);
  }
  console.log(kanjiDecArr);

  // 漢字を全て英語変換
  // 漢字変換APIからもらうデータの構造と同じに
  let enArr = [];
  for (let i = 0; i < kanjiDecArr.length; i++) {
    enArr.push(await getEnglish(kanjiDecArr[i]));
  }
  console.log(enArr);

  // 英語からカタカナ変換
  let katakanaArr = [];
  for (let i = 0; i < enArr.length; i++) {
    katakanaArr.push(await getKatakana(enArr[i]));
  }
  console.log(katakanaArr);

  // ・をつけてかっこよく,文字列に
  let wkWord = katakanaArr.join("");
  console.log(wkWord);
  // process.stdout.write(wkWord);

  return {
    kanji: kanjiDecArr,
    en: enArr,
    katakana: katakanaArr,
    text: wkWord
  };
}

module.exports = main;


結果

入力は同じでもランダムがあるので逆に面白いときもある
以下は結果のランダム具合をカンマ区切りでいくつか出してみます

おもしろい → サーフィス・ワイト,メーン・シライ,ヘビストーン・リード
かわいい → チューアーン・グッド,スキン・イー,ボート・セー
まじやばい → マミヤ・ホースドクタ,ロード・ヤバイ
ちょべりば → アリタル・レーン,スレッド・バーリバ,フォー・ビリーフ
ありえない → グッドラック・アグリ,イェス・イットイズインポサブル

考察

う〜ん...
作ってるときはランダムでの抽出はどうなんだって思っていましたが,それよりも英語からカタカナ変換が致命的にわからなくなります.
そもそも普段使わない英語が出てくると「ホワイトキック感」がでないですね.
もしかしたらボトムアップ方式で簡単な英語からword2vecなどで近い言葉を選出してそれらで構成するほうがいいのかもしれません.
http://www.eigo-duke.com/tango/tangoindex.html

8
0
2

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
8
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?