• 【C++】TwitterのJsonデータとれたのでpicojsonを試してみた備忘録

    2016-10-10 21:58
    前回Jsonデータとることに成功したのでC++で使えるJsonパーサーを色々と試してみました。
    色々みた感じpicojsonが導入簡単そうだし便利ってことで入れてみた。

    導入はここのpicojson.hを開いてコピー
    VisualStudioの
    新しい項目でpicojson.hを作ってペーストするだけ
    いやー簡単ですね 凄い簡単。感動。
    ってことで作ったあとはmain.cpp
    #include "picojson.h"
    を一番上に入力。簡単。

    で、今度は試しに前回のmain.cppのmain関数のreturn前に

    std::string data;
    wchar_t str2[512];
    char str3[512];


    //読み込み
    std::ifstream ifs(【JSONNAME】);
    picojson::value v;
    ifs >> v;

    //エラー処理
    std::string err = picojson::get_last_error();
    if (!err.empty()){
    std::cerr << err << std::endl;
    return 1;
    }

    //パーサー動かすところ
    if (v.is<picojson::array>()){
    picojson::array& a = v.get<picojson::array>();
    for (picojson::array::iterator i = a.begin(); i != a.end(); ++i){

    //ここには投稿者名出力させたい
    //まだ書いてない

    //Twitterのタイムラインを出力するところ
    picojson::object&obj = (*i).get<picojson::object>();
    data = obj["text"].get<std::string>();
    //UTF-8からShift-JISに変換
    MultiByteToWideChar(CP_UTF8, 0, data.c_str(), strlen(data.c_str()) + 1, str2, MAX_PATH);
    WideCharToMultiByte(CP_ACP, 0, str2, sizeof(str2) / sizeof(str2[0]), str3, sizeof(str3), NULL, NULL);
    std::cout << str3 << "\n" << std::endl;

    }
    }

    と書く。
    UTF-8は一旦Unicodeにしないといけないようなので、UnicodeにしてS-JISに変換。
    エンコード処理はWindows.hをインクルードしないといけないので
    #include <Windows.h>
    を入力。
    保存Jsonファイル名の【JSONNAME】は各自設定してあげてください。

    出力して実行。

    一応タイムラインは取得できたと思う。


    次に投稿者名を取得したいけどuserってオブジェクトを一旦取得しないといけないようなので

    picojson::object&user = obj["user"].get<picojson::object>();
    //ユーザネーム取得
    data = user["name"].get<std::string>();
    //UTF-8からShift-JISに変換
    MultiByteToWideChar(CP_UTF8, 0, data.c_str(), strlen(data.c_str()) + 1, str2, MAX_PATH);
    WideCharToMultiByte(CP_ACP, 0, str2, sizeof(str2) / sizeof(str2[0]), str3, sizeof(str3), NULL, NULL);
    std::cout << str3 << " : "<< std::endl;

    をまだ書いてない部分に入力。
    出力するとできたっぽい。





    (10/10 23:37追記)
    (10/11 3:02追記)
    コンソール上じゃ特殊文字で死ぬのでこの追記はなかったことにしてください

    //UTF-8からShift-JISに変換
    MultiByteToWideChar(CP_UTF8, 0, data.c_str(), strlen(data.c_str()) + 1, str2, MAX_PATH);
    WideCharToMultiByte(CP_ACP, 0, str2, sizeof(str2) / sizeof(str2[0]), str3, sizeof(str3), NULL, NULL);
    std::cout << str3 << " : "<< std::endl;
    としてましたが
    //UTF-8からShift-JISに変換
    MultiByteToWideChar(CP_UTF8, 0, data.c_str(), strlen(data.c_str()) + 1, str2, MAX_PATH);
    //アッカリ~ン
    std::wcout << str2 << " : "<< std::endl; //アッオリ~ン
    こっちのほうが良さそうですね


    参考文献
    (10/11 4:42追記:リンク先間違ってたようなのでリンクつなげ直しました)
    GitHub - a header-file-only, JSON parser serializer in C++
    GET statuses/home_timeline - ホームタイムラインを取得
    俺でもわかるPicojsonの使い方
    boost::property_treeで日本語を含むJSONが文字化けする


  • 広告
  • 【C++】Twitterのタイムラインを取得したかった備忘録みたいなもの(Twicpps使用)

    2016-10-10 05:53
    目次
    0.別に読まなくてもいいこと
    1.自分の環境
    2.下準備:OpenSSL用意&Twicpps動作確認  ←入れ方から知りたい方はここから
    3.本題:改造  ←改造方法だけ知りたい方はここから
    4.実行結果、考察、感想
    5.参考文献


    0.別に読まなくてもいいこと

    なんか色々あったけど別にどうでもいいことだし、何はともあれとりあえずC言語でTwitterAPIいじりたかった(ぉぃ
    で、とりあえず色々試してみたけどこことか見た感じTwicppsとか面白そうだなって思ってそれ使ってみましたん
    で、「おー、呟けたー」って思ったんですが、今度はTL取得したいなって思ったので色々いじってみました(ぇ
    他の言語のが簡単なのはわかってますがバカのひとつ覚えでとりあえずCを貫きたかったのだ(
    とりあえず他の言語でもいいよって人はTwitter4Jでも使ってれば良いんじゃないかなと
    ○○のが楽だよとかそういうわかりきったコメントは別に求めてません(
    Linux環境だったりMinGWだったりとか使ってるのしか出なかったので、VisualStudioで実行したよーっていうメモみたいなものです。はい。
    一応自分なりに忘れた時用にメモがてら書いてこうかなと
    悩んだ結果、案外簡単な改造だったのでまぁ分かる人には何を今更って感じなんだろうなと思いながらカキカキ


    書き忘れてることがあるかもしれないので
    うまく動かなかったらコメントください。


    1.自分の環境
    • OS: Windows8.1 64Bit
    • 環境:Visual Studio 2013
    • Cの経験:Hello World書けます
    • プログラミング経験:自宅PCにVisual Studio入れて満足しました
    • 手元にあるもの:金麦
    • あると便利なもの:柿ピー、ラーメン

    2.下準備:OpenSSL用意&Twicpps動作確認
    OpenSSLをコンパイルするのは面倒なので適当にここからコンパイル済みのものをDLします
    とりあえず強そうな一番最新のLightじゃない方を選びます(ぇ
    Twicppsの配布ページの通り設定・・・といきたかったのですが、

    今回OpenSSLのインストーラー使ったので
    追加のインクルードディレクトリはC:\OpenSSL-Win32-102h\include
    追加のライブラリディレクトリはC:\OpenSSL-Win32-102h\lib
    を設定。


    main.cpp
    //#include "../keys/mykey.h"
    //#include "../keys/soramimi_jp.h"
    #include "../keys/soramimi_jp_bot.h"

    #include "../keys/mykey.h"
    だけにしてkeysファイル内のmykey.hのconsumer_key,consumer_sec,accesstoken,accesstoken_secを入力。
    とりあえずコンパイルしてちゃんと動くか確認

    通ったら成功。やったねたえちゃん。
    通らなかったらインクルードディレクトリとかの設定が怪しいと思うから個人個人でちゃんと確認しながら設定オナシャス。
    コマンドプロンプト開いてプロジェクトのexe出力先に移動。
    [exeファイル名] "[つぶやき内容]"
    で呟ければ成功。



    3.本題:改造
    とりあえずmainを見て分かる通りTwitterClientクラスのtweet関数で呟く処理を行っとるようなのでtweet.cppを開く。
    bool TwitterClient::tweet(std::string message, std::vector<std::string> const *media_ids){

    // 中略 //

    oauth::Request oauth_req = oauth::sign(url.c_str(), oauth::POST, keys());
    std::string res;
    RequestOption opt;
    char const *p = oauth_req.post.c_str();
    opt.set_post_data(p, p + oauth_req.post.size());

    return request(oauth_req.url, opt, &res);
    }

    って関数があるからまるごとコピーして引数全消去、関数名変更。
    今回はbool TwitterClient::Timeline()としました。
    次に以下の赤字を全消去。

    bool TwitterClient::Timeline()
    {
    if (message.empty()) {
    return false;
    }

    // convert message to utf-8
    #ifdef _WIN32
    message = sjis_to_utf8(message);
    #else
    //message = conv("utf-8", "euc-jp", message);
    #endif

    std::string url = "https://api.twitter.com/1.1/statuses/update.json";

    url += "?status=";
    url += url_encode(message);
    if (media_ids && !media_ids->empty()) {
    std::string ids;
    for (std::string const &media_id : *media_ids) {
    if (!media_id.empty()) {
    if (!ids.empty()) {
    ids += ',';
    }
    ids += media_id;
    }
    }
    if (!ids.empty()) {
    url += "&media_ids=";
    url += ids;
    }
    }

    oauth::Request oauth_req = oauth::sign(url.c_str(), oauth::POST, keys());
    std::string res;
    RequestOption opt;
    char const *p = oauth_req.post.c_str();
    opt.set_post_data(p, p + oauth_req.post.size());

    return request(oauth_req.url, opt, &res);
    }




    で、今回はタイムラインを取得したいので
    std::string url = "https://api.twitter.com/1.1/statuses/update.json";

    std::string url = "https://api.twitter.com/1.1/statuses/home_timeline.json";
    に変更。
    とりあえずstd::string urlの1行下にクエリとして
    url += "?count=10";
    を申し訳程度に入力。とりあえず動いたら関数の引数で数値変えれるようにしましょう(ぇ



    次に

    oauth::Request oauth_req = oauth::sign(url.c_str(), oauth::POST, keys());
    std::string res;
    RequestOption opt;
    char const *p = oauth_req.post.c_str();
    opt.set_post_data(p, p + oauth_req.post.size());
    return request(oauth_req.url, opt, &res);

    を編集。
    今回GETのAPI使うので
    oauth::Request oauth_req = oauth::sign(url.c_str(), oauth::POST, keys());
    の行を
    oauth::Request oauth_req = oauth::sign(url.c_str(), oauth::GET, keys());
    に変更。
    次に
    opt.set_post_data(p, p + oauth_req.post.size());
    の行を
    opt.set_get_data(p, p + oauth_req.post.size());
    に変更。
    set_get_data()は定義されてないので定義します。
    tweet.h

    void set_post_data(char const *begin, char const *end)
    {
    post_begin = begin;
    post_end = end;
    method = POST;
    }

    をコピーして真下に

    void set_get_data(char const *begin, char const *end)
    {
    post_begin = begin;
    post_end = end;
    method = GET;
    }

    に変更。
    これでOKかーって思ったら404エラー出ました。
    なんでやーって思って色々探した結果、oauth.cppのbuild_url()が悪さしてるようです。
    POSTなら問題無かったのに・・・

    oautch.cppを開いて
    std::string oauth::build_url(std::vector<std::string> const &vec, int start)
    試しにこの関数をまるごとコピーしてGET用に
    std::string oauth::build_url2(std::vector<std::string> const &vec, int start)
    とします。

    std::string oauth::build_url2(std::vector<std::string> const &vec, int start)
    {
    const char sep = '&';
    std::string query;
    for (size_t i = start; i < vec.size(); i++) {
    std::string s = vec[i];
    if (i > 0) {
    char const *p = s.c_str();
    char const *e = strchr(p, '=');
    if (e) {
    std::string name(p, e);
    std::string value = e + 1;
    s = name + '=' + url_encode(value);
    } else {
    s += '=';
    }
    }
    if (!query.empty()) {
    query += sep;
    }
    query += s;
    }
    return query;
    }

    赤字のところを

    if (!query.empty()) {
    query += sep;
    }

    から

    if (!query.empty()) {
    if (i >= 2){
    query += sep;
    }
    else{
    query += "?";
    }

    }

    に変更。
    これに合わせて

    oauth::Request oauth::sign(const char *url, http_method_t http_method, const Keys &keys)
    {
    std::vector<std::string> vec;
    split_url(url, &vec);

    process_(&vec, http_method, keys);

    if (http_method == POST) {
    Request req;
    req.post = oauth::build_url(vec, 1);
    req.url = vec.at(0);
    return req;
    } else {
    Request req;
    req.url = oauth::build_url(vec, 0);
    return req;
    }
    }

    赤字の箇所を
    req.url = oauth::build_url(vec, 0);
    から
    req.url = oauth::build_url2(vec, 0);
    に変更。
    次にoauth.hを開いて
    static std::string build_url(const std::vector<std::string> &argv, int start);
    の下に
    static std::string build_url2(const std::vector<std::string> &argv, int start);
    を入力。
    これでちゃんと動作するようになったと思う。


    レスポンスは*resに入ってるので、次にtweet.cpp開いて

    bool ok = request(oauth_req.url, opt , &res);


    return ok;

    の箇所に

    /* ファイルに書き出す */
    FILE *fp;
    if ((fp = fopen("test.json", "w")) == NULL){
    printf("Output File Error\n");
    exit(0);
    }
    fprintf(fp,"%s",res.c_str());
    fclose(fp);


    と書き出し処理行っちゃいましょう。
    最後にmain.cpp開いて

    ok = tc.tweet(message, &media_ids);

    の箇所を

    //ok = tc.tweet(message, &media_ids);
    ok = tc.Timeline();

    と変更。

    4.実行結果、考察、感想
    実行結果は以下のようになった。

    Jsonファイルの取得に成功した。
    当初の予定通りJsonファイルの取得という課題は満たすことができた。
    今後の課題としては、Jsonのデータの取扱いや、Timeline()関数での取得数等あるが、今回はクエリがcountのみだったので、max_id等も使うようにしたい。

    疲れたし腹減った。寝る。

    5.参考文献


  • マリオメーカーのコースデザインとかの基本的なアレ

    2016-09-05 17:52
    なんか某所で「イイネが増えないぞぉ やってもらってもイイネつかないぞぉ」って嘆いてた人がいて「あぁ、ステージデザイン的に誰もつけんだろうな」って思った状況に直面したので、似たようなことで悩む人向けに。
    こういうこと言ったら「俺にデザインセンス求めるな」みたいになぁなぁで終わったので当の本人はどうなったかしらんけど
    あと「こういうグチャグチャデザインっていう世界観なんだけどなぁ」や「個性です!」みたいなのは知らんわ。勝手にやってろ。

    あくまで経験則とかで語ってるので「これが絶対とは言いません」し、もっといい解決法もあると思います。
    あくまで「とりあえず最低限のことはやっておきたい」って人向けなので、作り慣れてる人向けには書いておりません。
    また悪意のある罠は控えろとか運ゲーは控えろとかのような論外な話題はここでは取り扱っておりません。
    ついでにデザインが綺麗になったからといって有名になったり彼女ができたり友達ができたりとかは保証しません。彼女や友達は別売りです。
    また「飾り付けの仕方」みたいなのは本記事では取り扱っておりません。

    思いつき次第更新します



    1:セメントブロックだけ








    2:地面が宙に浮いてる



    もしくは






    3:トゲだらけ








    4:コの字型







    5:土管の尻が切れてる(キノコ足場等も同じ)



    もしくは

    ここは用途によって使い分けとかしたほうがいいと思う。
    右側のように土管である必要性がない場合は普通の地面にした方がいいし。



    6:地面の謎勃起