ソースコード

前回と同じくソースコードを公開します.
ツッコミなどをコメントに書いていただけたら感激ですd(・・

/*!
*  \file   main.cpp
*/
#include <iostream>
using namespace std;

#include "./twitterStreaming.hpp"

#define CR 13
#define LF 10

void
*myrealloc(void *ptr, size_t size)
{
    /* There might be a realloc() out there that doesn't like reallocing
    NULL pointers, so we take care of it here */
    if(ptr)
        return realloc(ptr, size);
    else
        return malloc(size);
}

size_t
curlCallback(void *ptr, size_t size, size_t nmemb, TwttrStrm::twitter &twitter)
{
    size_t realsize = size * nmemb;

    twitter.mp_responseBuffer = (char *)myrealloc(twitter.mp_responseBuffer, twitter.m_responseSize+realsize+1);
    if (twitter.mp_responseBuffer)
    {
        memcpy(&(twitter.mp_responseBuffer[twitter.m_responseSize]), ptr, realsize);
        twitter.m_responseSize += realsize;
        twitter.mp_responseBuffer[twitter.m_responseSize] = '\0';
    }

    if (CR == twitter.mp_responseBuffer[twitter.m_responseSize-2] && LF == twitter.mp_responseBuffer[twitter.m_responseSize-1]) // Tweet を一つ受け取りきったら入る
    {
        if (!twitter.loadJson())
        {
            exit(0);
        }
    }

    return realsize;
}

int
main(int argc, char **argv)
{
    using namespace TwttrStrm;
    twitter twttr;

    // cURL
    CURL *curl_handle;
    CURLcode res;

    curl_handle = curl_easy_init();

    //  Twitter ログイン
    curl_easy_setopt(curl_handle, CURLOPT_PROXY, "192.168.0.1:8080");
    curl_easy_setopt(curl_handle, CURLOPT_PROXYUSERPWD, "PROXY_USER_NAME:PROXY_PASSWORD");
    curl_easy_setopt(curl_handle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY);
    curl_easy_setopt(curl_handle, CURLOPT_USERPWD, "TWITTER_ID:TWITTER_PASSWORD");

    // babel
    babel::init_babel();    

    if(curl_handle)
    {
        //curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?follow=5835402");    //  ID が「5835402」の人を追いかける
        //curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?track=%23ppfun");    //  「#ppfun」というキーワードを追いかける
        curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/sample.json");                   //  サンプル

        /* send all data to this function  */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, curlCallback);

        /* we pass our 'chunk' struct to the callback function */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &twttr);

        res = curl_easy_perform(curl_handle);

        /* always cleanup */ 
        curl_easy_cleanup(curl_handle);
    }

    return 0;
}
/*!
 *  \file   twitter.hpp
 */
#ifndef _TWITTER_STREAMING_HPP_
#define _TWITTER_STREAMING_HPP_

#include <map>
#include <string>
using namespace std;

#include "./curl/curl.h"
#include "./babel/babel.h"
#include "./picojson.h"

namespace TwttrStrm
{
class twitter
{
public:
    twitter();                      //!< コンストラクタ
    ~twitter();                     //!< デストラクタ

    bool loadJson();                //!< json から Tweet の情報を受け取る

public:
    //  cURL
    char   *mp_responseBuffer;      //!< Twiter の StreamingAPI から流れ込んでくる Tweet
    size_t  m_responseSize;         //!< mp_reponseBuffer のサイズ

private:
    //  Twitter
    string  m_twitterUsrName;       //!< Twitter のユーザ名
    string  m_twitterUsrPasswd;     //!< Twitter のパスワード
    map<string, string> m_statuses; //!< Tweet の情報 <reply, mention>
};

}   //  namespace TwttrStrm
#endif  // _TWITTER_STREAMING_HPP_
/*!
 *  \file   twitter.cpp
 */
#include "twitterStreaming.hpp"
#include "json.hpp"
#include "./babel/babel.h"

namespace TwttrStrm
{

twitter::twitter():
mp_responseBuffer(NULL),
m_responseSize(0),
m_twitterUsrName(""),
m_twitterUsrPasswd("")
{
}

twitter::~twitter()
{
}

bool
twitter::loadJson()
{
    using namespace picojson;
    string err; //  エラーメッセージを受け取る
    value v;
    parse(v, mp_responseBuffer, mp_responseBuffer + m_responseSize, &err);

    if (err.empty())    //  正常に受け取れた
    {
        object2map(v.get<object>(), m_statuses);    //  要素を全て抜き出す

        for (map<string, string>::iterator it = m_statuses.begin(); it != m_statuses.end(); it++)
        {
            cout << it->first << ": " << it->second << endl;
        }
        cout << endl;
        m_statuses.clear();

        mp_responseBuffer = NULL;
        m_responseSize    = 0;
    }
    

    return true;
}
}   //  namespace TwttrStrm
/*!
 *  \file   json.hpp
 */
#ifndef _JSON_HPP_
#define _JSON_HPP_

#include <map>
#include <string>
using namespace std;

#include "./babel/babel.h"
#include "./picojson.h"

void
object2map(picojson::object &obj, map<string, string> &mp);

#endif  //  _JSON_HPP_
/*!
 *  \file   json.cpp
 */
#include "json.hpp"

void
object2map(picojson::object &obj, map<string, string> &mp)
{
    for (picojson::object::iterator it = obj.begin(); it != obj.end(); it++)
    {
        string s = babel::utf8_to_sjis(it->second.to_str());
        if (s == "object")
        {
            object2map(it->second.get<picojson::object>(), mp);
        }
        else
        {
            mp.insert(map<string, string>::value_type(it->first, s));
        }
    }
}

いい加減ソースコードも長くなったし見にくいですね.
行番号とスクロールバーが欲しいです.
WordPress あたりに移ろうかな(・・;

キーワードや ID を指定して Tweet を持ってくる

これは取りに行く json を変えるだけですね.
複数のキーワードや人を追いかけるときはカンマでつなげればいいらしいです.
詳しくは wiki で確認できます.


2行目の ID は僕の ID です.
RSS フィードの URL から確認したのですが,もっとスマートな方法があればいいですね.
普通の Twitter API を使えば持って来れそうな気もします.

// 「#ppfun」というキーワードを追いかける
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?track=%23ppfun");
// ID が「5835402」の人を追いかける
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/filter.json?follow=5835402");
// ついでにサンプル
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/sample.json");

キーワードや ID で追ったり,Tweet の情報をごっそり集めたりしてみる

きっかけやお世話になった方々についてはこちら「Twitter の Streaming API を C/C++ でいじってみた(1)」へどうぞ.

とりあえず statuses/sample を持ってくる

pingpong003ワークショップ@公立はこだて未来大学」に参加したのがきっかけで,「#ppfun」というハッシュタグを付けたつぶやきを流すアプリケーションをひそかに作っています.


そこで見つけたのがこれ,TwitterStreaming APIをいじってみました.
キーワードやユーザIDなどでつぶやきにフィルタをかけて,リアルタイムに取得できるみたいです.
Twitter クライアントというよりは,つぶやきを流し続けたり,蓄積して分析したりするような使い方をするならとっても適しているような気がします.


まだ直さないといけないところが残っていますが,とりあえず statuses/sample からつぶやきとニックネームを取得して出力するものを公開します.
statuses/filter を使ったものももうすぐ公開します.


今回お世話になったみなさん,とてもとても感謝です.

[追記]
isLimit 関数ですが,delete が来るおは受け取ったステータスに欠落部分がある時でしたね.

#include <iostream>
using namespace std;

#include "./curl/curl.h"
#include "./babel/babel.h"
#include "./picojson.h"
using namespace picojson;

#define CR 13
#define LF 10

struct MemoryStruct
{
    char *memory;
    size_t size;
};

bool
isLimit(value *pv)
{
    value obj = pv->get("delete");
    if (obj == NULL)
        return false;
    else
        return true;
}

static void
*myrealloc(void *ptr, size_t size)
{
    /* There might be a realloc() out there that doesn't like reallocing
    NULL pointers, so we take care of it here */
    if(ptr)
        return realloc(ptr, size);
    else
        return malloc(size);
}

static size_t
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, MemoryStruct *data)
{
    size_t realsize = size * nmemb;

    data->memory = (char *)myrealloc(data->memory, data->size + realsize +  1);
    if (data->memory)
    {
        memcpy(&(data->memory[data->size]), ptr, realsize);
        data->size += realsize;
        data->memory[data->size] = 0;
    }
    
    //  picojson
    if (CR == data->memory[data->size-2] && LF == data->memory[data->size-1])   //  Parsing Responses
    {
        value v;
        string err;
        parse(v, data->memory, data->memory + data->size, &err);
        
        if (isLimit(&v))    //  Track Limiting
        {
            exit(0);    //  cleanup してない
        }

        if (err.empty())
        {
            const string key("usr");
            object obj = v.get<object>();
            value  usr = v.get("user");

            object obj_usr = usr.get<object>();
            string screen_name(obj_usr["screen_name"].to_str());
            string text(obj["text"].to_str());
            cout << screen_name << ": " << babel::utf8_to_sjis(text) << endl;

            data->memory = NULL;
            data->size   = 0;
        }
    }

    return realsize;
}

int
main(int argc, char **argv)
{
    // babel
    babel::init_babel();    

    // cURL
    CURL *curl_handle;
    CURLcode res;
    struct MemoryStruct chunk;

    chunk.memory=NULL; /* we expect realloc(NULL, size) to work */ 
    chunk.size = 0;    /* no data at this point */ 
    curl_handle = curl_easy_init();

    curl_easy_setopt(curl_handle, CURLOPT_PROXY, "192.168.0.1:8080");
    curl_easy_setopt(curl_handle, CURLOPT_PROXYUSERPWD, "PROXY_USER_NAME:PROXY_PASSWORD");
    curl_easy_setopt(curl_handle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY);
    curl_easy_setopt(curl_handle, CURLOPT_USERPWD, "TWITTER_ID:TWITTER_PASSWORD");

    if(curl_handle)
    {
        curl_easy_setopt(curl_handle, CURLOPT_URL, "http://stream.twitter.com/1/statuses/sample.json");

        /* send all data to this function  */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

        /* we pass our 'chunk' struct to the callback function */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

        res = curl_easy_perform(curl_handle);

        /* always cleanup */ 
        curl_easy_cleanup(curl_handle);
    }
    return 0;
}

さて,libcurl や picojson をもっと上手に使えるように勉強しなくちゃ_〆(・・o)

Problem33

/*
 * \file   problem033.cpp
 * \brief  Project Euler - Problem33
 *
 * \author Takushi Homma (b1006018@fun.ac.jp)
 */
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

#define LMT 100

bool
isNontrivial(int e, int d, int *pe, int *pd)
{
    if (d%10 == 0 && d%10 == 0)
    {
        return false;
    }

    int tmpe, tmpd;
    if (e/10 == d/10)
    {
        tmpe = e%10;
        tmpd = d%10;
    }
    else if (e%10 == d/10)
    {
        tmpe = e/10;
        tmpd = d%10;
    }
    else if (e/10 == d%10)
    {
        tmpe = e%10;
        tmpd = d/10;
    }
    else if (e%10 == d%10)
    {
        tmpe = e%10;
        tmpd = d%10;
    }
    else
    {
        return false;
    }

    float a1 = (float)e / (float)d;
    float a2 = (float)tmpe / (float)tmpd;

    if (a1 == a2)
    {
        *pe = tmpe;
        *pd = tmpd;
        return true;
    }
    else
    {
        return false;
    }

    return false;
}

int
main(int argc, char **argv)
{
    vector<int> ve, vd;
    
    for (int d = 10; d < LMT; d++)
    {
        for (int e = 10; e < d; e++)
        {
            int tmpe, tmpd;
            if (isNontrivial(e, d, &tmpe, &tmpd))
            {
                ve.push_back(tmpe);
                vd.push_back(tmpd);
            }
        }
    }

    int e = 1, d = 1;
    
    for (vector<int>::iterator it = ve.begin(), end = ve.end(); it != end; it++)
    {
        e *= *it;
    }
    for (vector<int>::iterator it = vd.begin(), end = vd.end(); it != end; it++)
    {
        d *= *it;
    }
    
    cout << d/e << endl;

    return 0;
}

Problem32

/*
 * \file   problem032.cpp
 * \brief  Project Euler - Probmel32
 *
 * \author Takushi Homma (b1006018@fun.ac.jp)
 */
#include <iostream>
#include <string>
#include <algorithm>
#include <set>
using namespace std;

int
main(int argc, char **argv)
{
    int ans = 0;
    set<int> set_ans;
    string  s = "123456789";

    do
    {
        for (unsigned int i = 1; i < 8; i++)
        {
            for (unsigned int j = i+1; j < 9; j++)
            {
                int num[3];
                int i_num = 0;
                memset(num, 0, 3*sizeof(int));

                for (unsigned int k = 0; k < s.size(); k++)
                {
                    if (k == i || k == j)
                    {
                        i_num++;
                    }
                    num[i_num] *= 10;
                    num[i_num] += s.at(k)-'0';
                }

                if (num[0]*num[1] == num[2])
                {
                    set_ans.insert(num[2]);
                }
            }
        }
    } while (next_permutation(s.begin(), s.end()));

    for (set<int>::iterator it = set_ans.begin(), e = set_ans.end(); it != e; it++)
    {
        ans += *it;
    }
    cout << ans << endl;
    

    return 0;

}