クフでダローバルな日記

タフでもグローバルもない

偶然俳句ツイートbotの解説とルール説明してみます

久々のブログです。
先日、偶然俳句ツイートbotというものを作りました。

とは言っても、botでもツイートしたたように内容とアイディア自体はちょっと前に話題になった偶然短歌bot(@)やここで一句bot(@と一緒です。特にここで一句botについては、twitterリプする以外ほぼ同じなのでパクリと言われてもしたかないかもしれませんね。すみません。

今回はこちらのまとめていただいたtogetter↓がかなりbuzzったようで、かなりフォローしていただきました。
つぶやきから五七五を検出して報告してくる偶然俳句botとの戦い - Togetterまとめ
期待してフォローしていただいて嬉しいのですが、フォローしていただいただけでは俳句を探索しないので、botがフォロバするまで少々お待ちください。
また、フォローが増えすぎたため頻繁に規制されたり取得漏れが起きたりしているようなので、普通に俳句をツイートされても通知できないことが多いようです。ご了承ください。

どういう基準、仕組みで俳句を探索しているのか分からないとよく言われているようなので、ここでルールと仕組みを簡単に解説しておきます。

基本ルール

文章の解析はmecab+IPA辞書

形態素解析にはmecabIPA辞書を利用しています。と言っても何言ってるかわからない方も多いかと思いますが、端的に言うと文章を解析してくれるソフト的なものを使っているわけです。具体的には公式サイトを見ていただけると分かりやすいかと思います。
MeCab: Yet Another Part-of-Speech and Morphological Analyzer
例えば、「柿食えば鐘が鳴るなり法隆寺」というものをmecabを用いて解析すると

柿	名詞,一般,*,*,*,*,柿,カキ,カキ
食え	動詞,自立,*,*,五段・ワ行促音便,仮定形,食う,クエ,クエ
ば	助詞,接続助詞,*,*,*,*,ば,バ,バ
鐘	名詞,一般,*,*,*,*,鐘,カネ,カネ
が	助詞,格助詞,一般,*,*,*,が,ガ,ガ
鳴る	動詞,自立,*,*,五段・ラ行,基本形,鳴る,ナル,ナル
なり	助詞,接続助詞,*,*,*,*,なり,ナリ,ナリ
法隆寺	名詞,固有名詞,組織,*,*,*,法隆寺,ホウリュウジ,ホーリュージ

というように解析してくれるわけです。それぞれの分解した要素の最後にその言葉の読みがあるので、これを利用すれば575のリズムになっているものを見つけるプログラムが作れるわけです。
ちなみに僕はmecabを使ってみたのはこれが初めてで、練習のために作ってみたのがこのbotだったりします。

音のルール
  • 「ぁぃぅぇぉゃゅょ」は全部0音換算(「しゃ」などは1音)
  • 「ー」「っ」は一音
  • 読み方がわからない言葉(英単語、記号など)が含まれるものは判定しない
  • 字余りはNG

字余りについては、許容してしまうとかなりの文章が俳句認定されてしまうため、残念ながらNGとしました。
今は割と致命的なバグがあるので、そのうち修正します。(小声)
また、僕は俳句について知識が全然無いのでなんかおかしい所があれば教えてください…

上/中/下の句の最初の単語のルール

俳句の最初の単語の品詞としてOKなのは、
[名詞,動詞,形容詞,形容動詞, 副詞, 連体詞, 接続詞, 感動詞, 接頭詞, フィラー]
のどれかです。
さらに、最初の単語の細かいルールとして、

  • 非自立動詞や接尾語はNG
  • 「ぁ」など小さい文字から始まるのはNG

というものもあります。
例えば「みかん食え/鐘が鳴るな/法隆寺」みたいなのは中の句が助詞から始まってるのでダメってことです。

上/中/下の句の最後の単語のルール
  • 接頭詞はNG

今のところこれだけです。
例えば「ちょっとまて/ちょっとまってよ/おにいさん」はOKですが「ちょっとまて/ちょっとまって/にいさーん」は接頭詞「お」が中の句の末尾に来ているのでNGということです。

下の句の最後の単語のルール
  • 活用語の場合、終止形のみ

要するに、連用止などを禁止するわけです。

全体的に割と厳しいルールを適用しているのですが、これはルールを緩くするとどう見ても575じゃないものまで575と認定してしまいがちで、さらにツイート数が増えると規制につながりやすくなるためです。最初はもっとザルだったんですが、リプによる指摘に対応していたら大分精度が上昇しました。ビッグデータって凄い(?)。

季語判定

どうにかしてここで一句botと差別化しようと思った苦肉の策がこちらの季語判定になります。
お気づきの方も多いと思いますが、季語は読みの音によって判定しています。これは掛詞に対応するためです。もちろん嘘です。
じゃあなぜ音で判定しているかというと、普通に単語で判定しようと思うと滅多に季語がなくなってしまい、つまらないからです。異論は認めません。
季語については現代俳句データベースなどからお借りしました。現在2529個の季語が登録されています。
ちなみにボジョレー・ヌーボー(冬)とかもあるようなので、これを含む俳句ができるのを楽しみにしてます。

即リプの仕組み

どうやら秒速リプが受けているようなのでちょっと解説しておきますが、実はこれ自体はそれほど難しいことをしていません。
というのも、TwitterにはStreaming APIというものがあり、例えばechofonなどのアプリでは、流れてきた情報(ツイート)からアイコン画像とユーザー名、ツイート内容だけ取り出して一つの「ツイート」として表示しているわけです。だから一々ロードする必要もないし、ツイートされてすぐ表示されているわけですね。

botではこのStreaming APIを利用し、流れてきたツイートからツイート内容を取り出し、俳句認定と季語探索をしてツイートしてます。
ちなみに現状ではツイート内容から俳句を探し、季語認定をするのに約0.5秒、ツイートするのに約0.3秒の計0.8秒もかかってしまっているので、暇があれば少し高速化しようかと思っています。

最後に

少し解説させていただきましたが、僕よりもここで一句botや偶然短歌botの作者さんの方が機能や精度が良いので、そちらも見ていただけると嬉しいです。
Ruby - Slackの会話を元に一句詠む - Qiita
形態素解析エンジンMeCabにて文章中から短歌を抽出 - inaniwa3's blog

新しい機能を追加しようと鋭意努力しているのですが、今月は若干忙しいので気ままにお待ち戴けると幸いです。

以下、参考文献です。
現代俳句データベース
MeCab: Yet Another Part-of-Speech and Morphological Analyzer
『東京都版国語便覧』浜島書店

3ステップで自分の同時通訳twitter botを作りましょう

お久しぶりです。ようやく学科にも慣れてきましたが、色々とつらいです。

さて、最近もちょくちょくtwitter botを作っていたわけですが、ちょっと前にこちらの記事が人気を博しているのを読みました。
自分をコピーするbotを作る - naoty.to_s
Deploy To Herokuボタンってそうやって使えるのか……と感化され、楽しそうだったので僕も作ってみました。
mazamachi/twitrans_bot

概要

グローバル化している今、あなたのツイートも世界に向けて発信しましょう。え?語学力が足りない?だったら翻訳してもらえばいいんです。Microsoftの高性能翻訳があなたのツイートを自動で翻訳し、botとしてツイートしてくれます。
基本となる物は既に作ってあるのでプログラミングスキルは一切不要です。
必要なステップはたった3つ。
1. Microsoftアカウントを翻訳用に認証
2. Twitter bot用アカウントの作成と認証
3. 既存のコードをHeroku上にアップして設定
です。
※今回は残念ながら鍵垢(非公開アカウント)には対応していません。時間があったら作ってみます。

Microsoftアカウントを翻訳用に認証

まずは翻訳してくれるようにmicrosoftで登録する必要があります。Microsoft Translator | Microsoft Azure Marketplace にアクセスし、右にあるリストから0円のものを購入しましょう。無料プランだけでも月2,000,000文字が翻訳できるので、ツイートを翻訳する程度なら全く問題ないはずです。
Microsoftアカウントを持っていなければ作るようお願いします。
f:id:SWIMATH2:20141121174610p:plain

次はSign In にアクセスし、アプリ登録をクリック。クライアントIDや名前、説明は自分で好きなもので構いません。リダイレクトURIも適当で構いません。この時表示されるクライアントIDと顧客の秘密をメモしておいてください。
大事なものなので人には教えないようにしてください
f:id:SWIMATH2:20141121174703p:plain

Twitter bot用アカウントの作成と認証

Welcome to Twitter - Login or Sign upにアクセスし、bot用アカウントを作ってください。これに関しては説明は不要でしょう。

次にTwitter Application Managementにアクセスし、Create New Appを押してMicrosoftの時と同様アプリ登録をします。ただし、この時ログインするアカウントはbotのアカウントにしてください。名前や紹介やURLを適当に入力して同意して進むと、botが作成されます。
f:id:SWIMATH2:20141121174834p:plain
ただし、この段階ではこのbotは投稿ができないので一番右の"Permissions"からRead and Writeに変更してUpdate Settingsを押してください。
f:id:SWIMATH2:20141121174904p:plain
その後「Keys and Access Tokens」タブの下の方から Create my access tokenを押してください。以下のように表示されたConsumer Key,Consumer Secret,Access Token,Access Token Secretをメモしておいてください。
f:id:SWIMATH2:20141121174920p:plain

既存のコードをHeroku上にアップして設定

最後です。mazamachi/twitrans_bot · GitHubにアクセスし、deploy to herokuボタンを押してください。(herokuのアカウントを持っていなければ作る必要があります)
下の方にパラメータの入力欄があるので、これまでにメモしておいたキーなどを入力してください。

パラメータ名 入力するもの
LANGUAGE_FROM 自分がツイートする言語 ※1
LANGUAGE_TO 翻訳した言語 ※1
MENTION_NOT_INCLUDE リプライを翻訳するか ※2
USER_IDS 翻訳させるアカウントのid(","で区切ってください) ※3
TRANS_CLIENT_ID MicrosoftでメモしたクライアントID
TRANS_CLIENT_SECRET Microsoftでメモした顧客の秘密
BOT_CONSUMER_KEY TwitterのConsumer Key
BOT_CONSUMER_SECRET TwitterのConsumer Secret
BOT_ACCESS_TOKEN TwitterAccess Token
BOT_ACCESS_TOKEN_SECRET TwitterAccess Token Secret

※1 言語の種類はen,jaのように略称で入力してください。それぞれ1つだけです。言語一覧はTranslator Language Codesで参照できます。
※2 リプライを翻訳するか決めます。デフォルトでは含めないようになっているので、リプライを含めたければこれを false に変えてください。(FALSEやFalseでもダメです)
ただしあまりオススメはしません。というのも、翻訳されたツイートがリプライとなって相手に届いてしまうからです。若干迷惑ですね。
※3 例えば、today_prime_bot,today_pi_bot, HatenastarRank のようにしてください。

そうしたらページ最下部の Deploy for Free をクリックして、最後の設定をします。まだbotは登録されただけで動いていないので Resources からDynosのEditをクリック、ドラッグして1に変えてください。(止めたいときは逆に0にすれば良いです)
f:id:SWIMATH2:20141121174943p:plain


以上でbot完成です。お疲れ様でした。もし何か修正したければ HerokuのSettingでReveal Config Varsから修正することが出来ます。
実際に動かした方でなにか不具合があれば、ぜひコメントなどでご報告をお願いします。アドバイスとかもしていただければ泣いて喜びます。

Cポインタ問題

どうでしょう。

#include <stdio.h>

int main(){
	char *s1[]={"az","qxv"};
	char *s2[]={"We","must","go"};
	//文字の重複が無いようにしています
	char **ps[]={s1,s2};
/*
1.以下のそれぞれについて、何が出力されるか答えよ
//文字列
	printf("%s\n",*s1);
	printf("%s\n",**ps );
	printf("%s\n",*(*ps+1));
	printf("%s\n",*(*(ps+1)));
	printf("%s\n",*(*(ps+1)+1));
//文字(括弧の位置によってどう変わるか問う)
	printf("%c\n",***ps);
	printf("%c\n",*(**ps+1));
	printf("%c\n",**(*ps+1));
	printf("%c\n",***(ps+1));
	printf("%c\n",(***ps+1));
	printf("%c\n",*(**ps+3));
//おまけ
	printf("%c\n",**(*(ps+1)+1));
	printf("%c\n",*(*(*(ps+1)+2)+1));
/*
2.上のように宣言されている時、
printf("%c\n", hogehoge);
とすることでaが出力される方法をできるだけ多く考えよ。
ただし、結局同じようなことをしているものは同じものと見なす。
*/
}

Googleフォームで「回答を編集」用URLを回答者にメールで送信する方法

ようやく学科も決まったので、久しぶりに更新します。僕は電磁気のためにこの学科に入ったんじゃないんだ。

Googleフォームって便利ですよね。僕も最近サークルの名簿を作った際に利用したし、学科でアンケートを取る際にも活用されていたのを見ました。
ただ、フォームで回答したものを回答者が再度編集するためには、回答時に出てくるURLを保存しておく必要があって、大抵の人は保存してないわけです。しかし、もっと簡単に保存する方法を調べても出てこない……
そこで、Googleフォームのスクリプトマネージャを用いて編集用URLを回答者に送信するスクリプトを組んでみました。
(とは言っても、ググって出てきた情報を繋ぎあわせただけですが…)

まず、回答者にメールを送信する方法です。
ASCII.jp:Googleフォームで自動返信システムをサクッとつくる (4/4)|Web制作をちょっと便利にするGoogle Apps Script入門
に詳しく書いてあるので、こちらを参考にしました。っていうかもう解説すること残ってないです。

次に編集用URLをスクリプトで取得する方法ですが、こちらにだいたい書いてあります。
Googleフォーム 再編集を許可したフォームで最後に出てくる「回答を編集」のURLを再取得する方法はありますか? - Google プロダクト フォーラム
Googleプラットフォームで言うとここClass FormResponse - Google Apps Script — Google Developers

上記のQ&Aではリストアップする方法なのですが、両者を組み合わせれば個別の回答に対して編集用URLを取得することができます。
それがこちら↓

function submitForm(e){
  var itemResponses = e.response.getItemResponses(); //回答のオブジェクトを取得
  var message = '';
  var username = '';
  var mail = '';
  for (var i = 0; i < itemResponses.length; i++) { //回答内容を取得
    var itemResponse = itemResponses[i];
    var question = itemResponse.getItem().getTitle();
    var answer = itemResponse.getResponse();
    if (question == '氏名(漢字)'){
      username = answer;
    }
    if (question == 'メールアドレス'){
      mail = answer;
    }
    message += (i + 1).toString() + '. ' + question + ': ' + answer + '\n';
  }
  var editURL = e.response.getEditResponseUrl(); //回答編集用URLを取得
  var title = '名簿情報が送信されました';
  var content = '以下の内容でフォームが送信されました。\n\n '
  + message
  +'\n回答を編集したいときは\n'+ editURL +'\nにアクセスしてください。';
  GmailApp.sendEmail(mail, title, content);
}

肝は
var editURL = e.response.getEditResponseUrl(); //回答編集用URLを取得
ですね。こうすることで、回答タイミングでの編集用URLを取得できるわけです。

このスクリプトでは、一応他の回答内容についても確認のため送信するようにしてあります。
もちろん、回答者のメールアドレスを知る必要があるので質問内容としてメールアドレスを聞く欄を回答必須で作っておく必要があります。
文章の内容を変えたいときはjavascriptの文字列の扱いについて少しだけ調べれば簡単にできると思います。

このスクリプト、地味にかなり便利だと思うのでGoogleフォームを使う人はぜひ使ってみてください。