7
2

More than 3 years have passed since last update.

どうやら魅力のタイトルづけは完全無敵のようですね

Last updated at Posted at 2020-01-29

どうやら魅力のタイトルづけは完全無敵のようですね

概要

なろう小説のタイトルをパロった技術ブログのタイトル自動生成プログラムを作成しました。

[2020/03/07追記]
Webアプリにしました。
なろうパロディ☆タイトルジェネレータ

Webアプリ化の記事はこちら
思いつきで作ったプログラムをSinatraに組み込みHerokuにデプロイする

プログラムの実行結果
キーワード: 魅力, タイトルづけ

出力
"どうやら魅力のタイトルづけは完全無敵のようですね"
"どうやら魅力の身体はタイトルづけ無敵のようですね"
"どうやら魅力の身体は完全タイトルづけのようですね"
"どうやら魅力の身体は完全無敵のタイトルづけですね"
"どうやらタイトルづけの魅力は完全無敵のようですね"
"どうやら私の魅力はタイトルづけ無敵のようですね"
"どうやら私の魅力は完全タイトルづけのようですね"
"どうやら私の魅力は完全無敵のタイトルづけですね"
"どうやらタイトルづけの身体は魅力無敵のようですね"
"どうやら私のタイトルづけは魅力無敵のようですね"
"どうやら私の身体は魅力タイトルづけのようですね"
"どうやら私の身体は魅力無敵のタイトルづけですね"
"どうやらタイトルづけの身体は完全魅力のようですね"
"どうやら私のタイトルづけは完全魅力のようですね"
"どうやら私の身体はタイトルづけ魅力のようですね"
"どうやら私の身体は完全魅力のタイトルづけですね"
"どうやらタイトルづけの身体は完全無敵の魅力ですね"
"どうやら私のタイトルづけは完全無敵の魅力ですね"
"どうやら私の身体はタイトルづけ無敵の魅力ですね"
"どうやら私の身体は完全タイトルづけの魅力ですね"

はじめに

最近の技術系記事は「中身の新鮮さ・分かりやすさ」の他に、以下のような「目を引くタイトル」というのが重要視されているような気がします。
あまり強い言葉を使うなよ…弱く見えるぞ 〜AIによって”やさしく”言い換えできてるかチェックしよう〜
…Outlookの送信メールが……消えた…?(12/24改修されたよ)

そのような目を引くタイトルの中でも、以下のライトノベルのようなタイトルをもじったタイトルが多数存在します。
この TypeScript が Hello, world! のくせに慎重すぎる
このPHPがテンプレートエンジンのくせに慎重すぎる (前篇)

しかし、このような秀逸なタイトルはつけることが難しいし、タイトルに時間をかけるのはたるいみたいな人もいると思います。

そこで、今回は技術記事のパロディタイトルを自動生成するプログラムを作成しました。

1. 「小説家になろう」からタイトルを収集する
2. タイトルを形態素解析する
3. タイトルの候補を複数出力する

プログラム

「小説家になろう」からタイトルを収集する

「小説家になろう」よりタイトルを収集するため、以下のドキュメントを頼りにAPIを叩きます。
https://dev.syosetu.com/man/api/
有名なものをとりたい。タイトルだけ欲しい。なるべく多くとりたい。出力はjsonで欲しい。という条件からパラメータには

order = favnovelcnt
of = t
lim = 500
out = json

を指定します。
実行のたびにAPIを叩くのは迷惑なので、収集したタイトルを保存します。
一連のコードは以下です。

require "uri"
require 'net/http'
require 'openssl'
require 'json'

def narou_get(title_path)
    uri = "https://api.syosetu.com/novelapi/api/?order=favnovelcnt&of=t&lim=500&out=json"

    uri = URI.parse(uri)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE

    req = Net::HTTP::Get.new(uri.request_uri)
    res = http.request(req)
    res_body = res.body

    hash = JSON.parse(res_body)
    titles = []
    for title in hash do
        titles.push(title["title"])
    end

    open(title_path, 'w') do |f|
        titles.each { |s| f.puts(s) }
    end
    return titles
end

タイトルを形態素解析する

収集したタイトルをどうパロディにしているか。
という問題に対して、今回は「タイトルの名詞の部分を指定したキーワードに置換する」という方法をとります。
MeCabを用いてタイトルを形態素解析し、タイトルの分かち書きと名詞の添字を返す関数を作成します。
少しややこしい処理になっているのは、形態素解析の結果が一つのStringで返ってくるためです。

require 'mecab'

def tagger_title(title)
    tagger = MeCab::Tagger.new
    t_tagger = tagger.parse(title).split()
    noun_idx = []
    original = []
    for i in (0..t_tagger.length-2).step(2) do
        if t_tagger[i+1].start_with?('名詞')
            noun_idx.push(i/2)
        end
        original.push(t_tagger[i])
    end
    return original, noun_idx
end

タイトルの候補を複数出力する

得られたタイトルをパロディタイトルに書き換えます。
タイトル中の名詞の数に対し、記事のキーワードを一意に決めるのではなく、以下の順列に従い候補を複数出力します。

{}_{タイトル中の名詞数} \mathrm{P}_{記事のキーワード数}

キーワードの方が多い時は、名詞数になるまで打ち切ります。
タイトルは乱数で適当に決めます。

keyword = ['魅力', 'タイトルづけ']
if File.exist?(title_path)
    titles = File.open(title_path, 'r').readlines
else
    titles = narou_get(title_path)
end

idx = rand(1..titles.length)
split_title, noun_idx = tagger_title(titles[idx])

if keyword.length > noun_idx.length
    keyword = keyword.slice(0..noun_idx.length)
end

candidate = noun_idx.permutation(keyword.length)

for c in candidate do
    original = Marshal.load(Marshal.dump(split_title))
    c.each_with_index do |i, j|
        original[i] = keyword[j]
    end
    p original.join
end

結果

複数のキーワードに対して、うまいタイトルが生成できるか試します。
キーワード: Python, Deep learning

出力
"PythonのDeep learning 異端召喚者はシナリオブレイカー"
"Pythonのカンナ Deep learning召喚者はシナリオブレイカー"
"Pythonのカンナ 異端Deep learning者はシナリオブレイカー"
"Pythonのカンナ 異端召喚Deep learningはシナリオブレイカー"
"Pythonのカンナ 異端召喚者はDeep learning"
"Deep learningのPython 異端召喚者はシナリオブレイカー"
"カンナのPython Deep learning召喚者はシナリオブレイカー"
"カンナのPython 異端Deep learning者はシナリオブレイカー"
"カンナのPython 異端召喚Deep learningはシナリオブレイカー"
"カンナのPython 異端召喚者はDeep learning"
"Deep learningのカンナ Python召喚者はシナリオブレイカー"
"カンナのDeep learning Python召喚者はシナリオブレイカー"
"カンナのカンナ PythonDeep learning者はシナリオブレイカー"
"カンナのカンナ Python召喚Deep learningはシナリオブレイカー"
"カンナのカンナ Python召喚者はDeep learning"
"Deep learningのカンナ 異端Python者はシナリオブレイカー"
"カンナのDeep learning 異端Python者はシナリオブレイカー"
"カンナのカンナ Deep learningPython者はシナリオブレイカー"
"カンナのカンナ 異端PythonDeep learningはシナリオブレイカー"
"カンナのカンナ 異端Python者はDeep learning"
"Deep learningのカンナ 異端召喚Pythonはシナリオブレイカー"
"カンナのDeep learning 異端召喚Pythonはシナリオブレイカー"
"カンナのカンナ Deep learning召喚Pythonはシナリオブレイカー"
"カンナのカンナ 異端Deep learningPythonはシナリオブレイカー"
"カンナのカンナ 異端召喚PythonはDeep learning"
"Deep learningのカンナ 異端召喚者はPython"
"カンナのDeep learning 異端召喚者はPython"
"カンナのカンナ Deep learning召喚者はPython"
"カンナのカンナ 異端Deep learning者はPython"
"カンナのカンナ 異端召喚Deep learningはPython"

キーワード: JavaScript, Github, Heroku, Bootstrap, Laravel

出力
"自称!平凡魔Laravelの英雄ライフ~BGithub魔HerokuなのにBootstrapを作ってしまった結果JavaScript"
"自称!平凡魔族のLaravelライフ~BGithub魔HerokuなのにBootstrapを作ってしまった結果JavaScript"
"自称!平凡魔族の英雄Laravel~BGithub魔HerokuなのにBootstrapを作ってしまった結果JavaScript"
"自称!平凡魔族の英雄ライフLaravelBGithub魔HerokuなのにBootstrapを作ってしまった結果JavaScript"
"自称!平凡魔族の英雄ライフ~LaravelGithub魔HerokuなのにBootstrapを作ってしまった結果JavaScript"
"自称!平凡魔族の英雄ライフ~BGithubLaravelHerokuなのにBootstrapを作ってしまった結果JavaScript"
"自称!平凡魔族の英雄ライフ~BGithub魔HerokuなのにBootstrapを作ってしまったLaravelJavaScript"
"Laravel!平凡魔族の英雄ライフ~BGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!Laravel魔族の英雄ライフ~BGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡Laravel族の英雄ライフ~BGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡魔Laravelの英雄ライフ~BGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡魔族のLaravelライフ~BGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡魔族の英雄Laravel~BGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡魔族の英雄ライフLaravelBGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡魔族の英雄ライフ~LaravelGithub魔Herokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡魔族の英雄ライフ~BGithubLaravelHerokuなのにチートダンジョンを作ってしまったBootstrapJavaScript"
"自称!平凡魔族の英雄ライフ~BGithub魔HerokuなのにLaravelを作ってしまったBootstrapJavaScript"
"Bootstrap!Laravel魔族の英雄ライフ~BGithub魔族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡Laravel族の英雄ライフ~BGithub魔族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡魔Laravelの英雄ライフ~BGithub魔族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡魔族のLaravelライフ~BGithub魔族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡魔族の英雄Laravel~BGithub魔族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡魔族の英雄ライフLaravelBGithub魔族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡魔族の英雄ライフ~LaravelGithub魔族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡魔族の英雄ライフ~BGithubLaravel族なのにHerokuを作ってしまった結果JavaScript"
"Bootstrap!平凡魔族の英雄ライフ~BGithub魔LaravelなのにHerokuを作ってしまった結果JavaScript"

数が多いので抜粋しました。
しかし、キーワードの数が多くても個人的には面白いものが生成できているので、有効そうです。

あとがき

思ったよりうまい生成ができているので、これからたくさん技術記事を書こうと思っています。

7
2
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
7
2