ラベル C# の投稿を表示しています。 すべての投稿を表示
ラベル C# の投稿を表示しています。 すべての投稿を表示

2014/01/04

[プログラミング]通貨のレート計算

,
 3つめは"A.2 Currency Calculator"です。通貨のレート計算ですね。問題文を読めば分かりますが、仕様は
  • 引数に10進数と、2つのISO 4217準拠の通貨コードみたいなのを与えるので、もう一つの通貨でいくらになるか計算する
  • プログラムで扱えない通貨コードならエラーを吐く
  • 引数が無い場合は、てきとーな解説を吐く
です。

むずかしいところ - 通貨レートの取得

さて、これを実現するのには一つ問題があります。それは「変動する通貨レートを、どうやって取得するか」です。問題の出題者さんは「1$ = \100だよね!」みたいな感じで軽く出題したのかもしれませんが…

 幸いにして、ネット上で最新の通貨レートのデータを取得できるサイトがあります。

クジラ 外国為替 確認 API (為替 RSS) - http://api.aoikujira.com/kawase/

 ほんとはこのデータ元のXurrencyのAPIを使おうと思っていたのですが、Pricingページに"only 29,99 eruos per year"と書かれてたので諦めました。

 なんとかXML形式なら扱えるだろう、ということで、今回はこれを使うことにします。

コード

とりあえずコード貼っておきます。
using System;
using System.Linq;
using System.Xml.Linq;

namespace Rate1
{
    class Program
    {
        /// <summary>
        /// 通貨リストを作成する関数。といっても面倒なので、currencies.xmlを作る。
        /// </summary>
        static void MakeCurrencyList()
        {
            // Currency List(Compliant to ISO 4217) can be get from http://api.aoikujira.com/kawase/
            // (you should replace ", " to "\", \"")

            //var currencyList = new List<string> {"eur", "gbp", "aud", "brl", "cad", "chf", "cny", "dkk", "hkd", "inr", "jpy", "krw", "lkr", "myr", "nzd", "sgd", "twd", 
            //                                "zar", "thb", "sek", "nok", "mxn", "bgn", "czk", "huf", "ltl", "lvl", "pln", "ron", "isk", "hrk", "rub", "try", "php", 
            //                                "cop", "ars", "clp", "svc", "tnd", "pyg", "mad", "jmd", "sar", "qar", "hnl", "syp", "kwd", "bhd", "egp", "omr", "ngn", 
            //                                "pab", "pen", "ils", "uyu", "usd"};

            //var savexml = new XElement("Currencies");
            //savexml.Add(currencyList.Select(item => new XElement("Currency", item.ToUpper())));
            //savexml.Save(@"currencies.xml");
        }

        static void Main(string[] args)
        {
            // 使用できる通貨リストを、currencies.xmlから読み込む。
            var path = @"currencies.xml";
            var currencyxml = XElement.Load(path);
            var currencyList = from currency in currencyxml.Elements()
                             select currency.Value;
                
            // 引数のチェックをする
            if (3 > args.Length)
            {
                Console.WriteLine("args < 3");
                return;
            }

            // パラメータ(価格、元の通貨、相手先の通貨)
            var price = 0.0;
            try
            {
                price = double.Parse(args[0]);
            }
            catch (FormatException fe)
            {
                Console.WriteLine(fe.Message);
                return;
            }

            var srcCurrency = args[1].ToUpper();
            var dstCurrency = args[2].ToUpper();
            // 扱ってない通貨を指定すると、前の変換結果が返ってくる。
            // なので、仮にこういうエラーチェックしてる。
            if(!(currencyList.Contains(srcCurrency))){ 
                Console.WriteLine(srcCurrency + @"は扱えないです");
                return;
            }else if(!(currencyList.Contains(dstCurrency))){
                Console.WriteLine(dstCurrency + @"は扱えないです");
                return;
            }

            // レート表のxmlをDLする
            var url = @"http://api.aoikujira.com/kawase/xml/" + srcCurrency.ToLower();
            var elem = XElement.Load(url);

            // xmlのkawase/resultがokでなかったらエラー
            if (elem.Element("result").Value != "ok")
            {
                Console.WriteLine("XML result isn't ok");
            }
            else
            {
                // xmlからレートを取得する
                var rates = from p in elem.Elements()
                            where p.Name.LocalName == dstCurrency
                            select p.Value;

                foreach (var rate in rates)
                {
                    // 結果を表示する(結果は1つのはず…)
                    try
                    {
                        Console.WriteLine("{0} {1} == {2} {3}", price, srcCurrency, price * double.Parse(rate), dstCurrency);
                    }
                    catch (FormatException fe)
                    {
                        Console.WriteLine(fe.Message);
                        return;
                    }
                }
            }
        }
    }
}

コードは大きく分けてMakeCurrencyList()とMain()の2つです。前者は、「プログラムが対応している通貨レートを保存しておくため、対応通貨を書いたXMLを作成する」関数です。それもネットから取得してくればいーじゃんと思うかもですが、

  • そもそも上のAPIは、Invalidな通貨を指定すると、前に取得が成功したデータが返ってくる(キャッシュ?)(/kawase/iiiとかにすると、その前に指定した/kawase/jpyとかが来た) → よって、返ってきたデータで通貨対応してるか判断できない
  • 1つの通貨を指定すると、対応した他の(54種の)通貨全てとのレートが出るけど、これを用いて対応通貨を取得するとしても、最初の1つは指定しないといけない
  • そもそもXurrencyも上のサイトも、対応通貨を別表で配布したりはしてない(HPにはテキストで書いてある、けどHTMLをDOMしたりするのも大変そう)
  • じゃあ元からデータで持っておこう
という話でした。"JPY"で他通貨取得の方がいいのかなあ…

 XML作成ですが、面倒だからxmlns名前空間とかは特に指定してないのですが、多分したほうがいいのですね…

var savexml = new XElement("Currencies");
savexml.Add(currencyList.Select(item => new XElement("Currency", item.ToUpper())));
savexml.Save(@"currencies.xml");
ここでは、XElementを用いて、
<Currencies>
<Currency>EUR</Currency>
<Currency>GBP</Currency>
</Currencies>
のようなXMLファイルを作成しています。最初にルートのCurrencies要素を作って、その子としてcurrencyListの各要素を追加しています。

// パラメータ(価格、元の通貨、相手先の通貨)
var price = 0.0;
try
{
    price = double.Parse(args[0]);
}
catch (FormatException fe)
{
    Console.WriteLine(fe.Message);
    return;
}
ここはargs[0]( = 元の通貨での額)をdoubleにしてます。Parse()出来なかった時のためにtry~catchしてますが、「tryスコープ中で変数を宣言すると、tryのスコープが終わった瞬間に見えなくなる」という厄介な問題があるので、最初にわざわざ書いてます。もしかしたらTryParse()の方がいいのかもしれない…

コーディング規則

オンリーワンなコーディング規則、多分あると思うんですけど、天下のMicrosoftさんが「こう書け!」って言ってるみたいですので、今回はこれになるべく沿うように書きました。

C# のコーディング規則 (C# プログラミング ガイド) - http://msdn.microsoft.com/ja-jp/library/ff926074.aspx

でもコメントの//後に半角開けるのって気持ち悪い…
Read more →

2014/01/03

[プログラミング]ファイル読み込み

,
 100 Little Programming Exercises – go-left Softwareの"A.5 Count Words and Lines"です。と言ってもファイルの文字数と行数を数えるだけですが… 改行コードの猥雑さ(LF、CR、CRLF)を叩き込む、文字列処理の練習ということなんでしょうか?でも面倒だったので、Fileクラス使って済ませました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace CountWordsandLines1
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("Specify a file name");
            }
            else
            {
                var filename = args[0];
                var encoding = Encoding.UTF8;
                // ファイルを読みこむ
                //if(File.Exists(filename)) //ファイルが存在するかは、File.Exists()か読み込み時例外のどっち?
                try
                {
                    var lines = File.ReadLines(filename, encoding);
                    Console.WriteLine("File name : {0} contains {1} words in {2} lines", 
                        filename, lines.Select(line => line.Length).Sum(), lines.Count());
                }
                catch (FileNotFoundException e)
                {
                    Console.WriteLine(e.StackTrace + "\n" + e.Message);
                }
                catch (System.Security.SecurityException e)
                {
                    Console.WriteLine(e.StackTrace + "\n" + e.Message);
                }
            }
        }
    }
}

 File.ReadLines(string, Encoding)はどうやら.NET 4.0追加の新しい関数らしいです。私は最初ストリームを使うものだと思ってました。で、この関数は面白いことに、返り値がIEnumerable<string>です。

.NET Framework 4 の基本クラス ライブラリの新機能 - http://msdn.microsoft.com/ja-jp/magazine/ee428166.aspx

 なので今回はこれを使って、LINQ拡張メソッドで文字数を数えてます。.Select(line => line.Length)で行ごとの文字数を数え、それを.Sum()で合計してます。
 行数は、1行毎にIEnumerable<string>に突っ込まれているので、この要素数になります。
 一応幾つかファイルを読み込んでみた結果では、合ってるみたいです。

ぎもん

  • ファイルを読み込むときに、やはりファイルが存在するかは確かめると思うんだけど、これはFile.Exists()を使って事前に確かめるべきなのか?File.ReadLines()してみてFileNotFoundExceptionをcatchすることで把握するべきなのか?
  • Encodingの問題 - 未知のファイルは多分事前にエンコーディングはわからないだろうけど、どうするんだろう。
  • 容量の大きすぎるファイル問題 - GB級ファイルの問題とか、メモリをどうするかとか
Read more →

[プログラミング]引数逆順

,
 お正月休みですね。といっても、バイトもなく、実家暮らしで暇なので、プログラミングの練習問題を探してはC#をごにょごにょしてます。

100 Little Programming Exercises – go-left Software - https://go-left.com/blog/programming/100-little-programming-exercises/

これのReverse The Inputです。引数は自動的に、スペースで区切られた単語ごとに配列に入れられるので、その配列を逆順にすればいいだけですが、最後の要素"END"は逆順にしません。

とりあえず書いたのは以下のコード。
static void Main(string[] args)
{
    var list = args.ToList();
    if (list.Last() != "END")
    {
        Console.WriteLine("args.Last() != \"END\"");
    }
    else
    {
        //http://melma.com/backnumber_120830_4798410/
        //IEnumerable<T>.Reverse()は範囲の指定ができない。
        //List<T>.Reverse()は範囲指定が出来るが、返り値がvoid。
        list.RemoveAt(list.Count() - 1);
        list.Reverse<string>().ToList().ForEach(arg => Console.WriteLine(arg));
    }
}

 例外処理はしておらず、LINQ拡張メソッドではなくList<T>の関数を呼んでるので、行数が多めだと思われます。
 本来は多分配列の逆順を実装する練習なんでしょうけど、各要素を後ろから挿入するくらいしか思いつかなかった…

 最初は最後の要素以外のReverse()(List<T>.Reverse(Int32, Int32))しようと思ったんですけど、RemoveしてIEnumerable<T>.Reverse()のほうがいい気がした。
 IEnumerableだかにForEachが無いから、ListのForEachを使うためだけにToList()してる(どうやら副作用回避のため実装してないけれど、皆同様の拡張メソッド作ってしまうみたいだね)。

LINQ拡張メソッドのTake()を使う

結局、自分が困っているのは「どうやって最後の要素以外を逆順するか?」ということで、上の例だとRemoveAt()を用いてList<string>から要素を削除して、それからReverse()して対処してるわけです。
 
 んでも拡張メソッド一覧見てたら、「配列の一部だけを抜き出す」というTake()を見つけたので、じゃあそっちのほうが一行で済むよね?ということでこうしました。
static void Main(string[] args)
{
    var endKey = "END";
    if (args.Last() != endKey)
    {
        Console.WriteLine("args.Last() != " + endKey);
    }
    else
    {
        //http://melma.com/backnumber_120830_4798410/
        //IEnumerable<T>.Reverse()は範囲の指定ができない。
        //List<T>.Reverse()は範囲指定が出来るが、返り値がvoid。
        args.ToList()
            .Take(args.Length - 1)
            .Reverse<string>()
            .ToList().ForEach(arg => Console.WriteLine(arg));
    }
}
このコードの問題は、args.ToList()した後に、argsのListを幾つ抜き出す(Take()する)かの指定に、Listする前のargsの要素数を参考にしているところ…本当だったらList<T>.Countを使うべきなんだろうけど、どうしたものか…
 これは病院から帰ってきて思いついたもの。

ぎもん

自分はLINQ星人ではないけれど、「最後の要素が○○ならプログラムを終わらせる」みたいなのを、もうちょっとスマートに書けたりしないかな。
Read more →

2014/01/02

[プログラミング]暗号の国のアリスと循環アルファベット++

,
 とてもタイトルに困ったんですが…とりあえず大した内容ではないです
 
 『暗号の国のアリス』(著:結城浩)の中でシーザー式暗号というものが取り上げられています。これは、暗号化したい平文のアルファベットをそれぞれ、アルファベット順にn文字前後にずらすといったものです。例えば、"abc"なら3文字ずらしで"def"といった具合です。
 で、この暗号はBrute Force Attackで破ることが出来るのですが、練習問題を解くプログラムを書いてて「どうやって実装すればいいんだろう???」って思ったときのメモです。

実装法1 - テーブルを使う

 どうしようか迷い、最初はテーブルを使うものにしました。つまり、string配列→char配列にし、それぞれの文字のn文字先を、予め用意したテーブルから持ってきます。この場合のキモは、n文字先がテーブルのどの要素に成るかの計算です(と言っても簡単なクイズレベルですけど)。難点としては、コードが長くなるのと、for文の中にforeachが入り二重ループになりそうなことです。

参考: C# でのアルファベットの文字の配列を生成 - http://ja.softuses.com/73951

 この時、大文字(0x41~0x5A)と小文字(0x61~0x7A)を分けるのが面倒だったので、最初の文字列を.ToLower()し、小文字に揃えました(今回はこれでオッケー)。

実装法2 - 拡張メソッドを使う

 で、さっきのページでC#の拡張メソッドを見て、「なんだもっと簡単に書けるじゃん」ということで、結局次のようになりました。
static void Main(string[] args)
{
    var str = "PELCGBTENCUL";  //対象文字列
    foreach(var i in Enumerable.Range(0, 26).ToArray())
    {
        Console.WriteLine("{0} : {1}", i, 
        new string(str.ToLower().Select(c => (char)('a' + ((i + c - 'a') % 26))).ToArray()));
    }
}
 すると、以下のようになり、13文字後ろにずらす(or??文字前にずらす)と、元の平文と思われる"cryptography"が分かります。
総あたり(といっても26回)した時の例
拡張メソッドはお勉強中なのですが、実践できる機会があってよかったです。
 コードとしては、
  • str.ToLower()で、まず小文字に統一します。
  • .Select()で、変数str中の各要素(char)に対して、そのi文字先(ただし、'z' + iなどはASCIIの小文字の範囲を超えるので、i文字先(i + c)から、先頭の文字を引き(- 'a')、更に26で割ることでどのアルファベットか割り出し(% 26)、オフセット0x61のために'a'を足す。という面倒なことをしています。
  • .ToArray()でchar[]にしています。
  • new string(...)は、char[]→stringにするときの常套手段みたいです。でもnewした割りにはその変数すぐ消えるし、なんかちょっと気持ち悪いですね…
拡張メソッドのように、関数の戻り値から、また数珠つなぎのように関数を呼び出し、1行に収めるのはなかなか楽しいですね。

ぎもん

この本では、この後の使い捨て暗号(ワンタイムパッド)が解読不可な理由として、「全ての平文の候補が登場するため、どれが答えかわからない」と説明されています。これには、全てが同じ平文とかが登場するから、と例で示されています。でも、シーザー式暗号のn(0 < n < 26)文字復元をしても、結局どれが平文か分からないような気もする…?(もしかしたら平文は単語ではないのかもしれない)
 結局、元の平文が人間味のある∧既知の単語∧平文候補が1つを覗いて辞書に載ってる単語じゃないとだめなのでは…
 こればかりは、使い捨てパッドが解読不可能である数学的証明を知らないと、真実に辿り着けなさそうですね…

 それと、暗号はやはり戦争に於いても利用されたようですが(ナチスドイツのエニグマetc)、「どうやって鍵を秘密裏に運ぶか」ということに苦心したんですね。前線の兵に秘密鍵を渡す方法というのも気になってきました。
Read more →

2013/07/08

[C#]SQL ServerのLocalDBを、Entity Data Modelで設計し生成する。

,
 C#でデータベースを使うお話です。私は初心者で、尚且つ情報をあまり上手に集められない人間なので、とても試行錯誤(或いは途方に暮れて迷うとも言う)しました。実際、ここに書くだけの内容を知るのにも、かなりの時間がかかりました。その覚書みたいなものです。

 まあデータベースと一口に言っても、実際には何種類も有りまして、例えばフリーライブラリのSqliteとか、MicrosoftのSQL Serverとかです。私のような情弱初心者だと、そもそもどれを使っていいかわからない…ということになってしまいました。
こんなにある…
上の写真は、VS2012で[サーバーエクスプローラー]ウィンドウで、[データ接続]を右クリック→[接続の追加]を選択した時のダイアログです。色んなデータベースの種類があります。例えば、
・SQL Server Compact 4.0とは、携帯向けのデータベースです。確か、データベースの容量や、使用出来るデータ型に制限があったような気がします。
・SQL Serverはその名の通りです。
・Access データベース ファイルとは、Microsoft Accessで用いるもの…なのでしょうか…?

 私の場合、データベースが必要といっても、アプリケーションを動かす場所は固定ではなく、ちょっとデータを保存したり読み込んだりできればいいので、保存場所はどちらかというとローカルの方が良いのです。なので、SQL Serverのうち、LocalDBと言うのを使うことにします。
//最初はLocalDBを知らなかったので、SQL Server Compact 4.0の方を使おうと頑張ってた… 
 LocalDBを作るには、[ソリューション エクスプローラー]でプロジェクト名を右クリック→[追加]→[新しい項目]で、[サービスベースのデータベース]を選択します。


 すると、このようなダイアログが出ると思います。ここでは、Entity Data Modelという機能を使いたいので、右の[Entity Data Model]を選択します。


 最初の段階から設計するので、ここでは[空のモデル]を選択。


 次に、Entity Data Modelでデータベースの設計をします。こんな画面が出てくると思います。ここでは、GUIツールを用いてぽちぽちとコンポーネントを配置することで、データベースのテーブルなどの設計図(のようなもの)を作っていきます。
 

 まず、右クリック→[新規追加]→[エンティティ]で、エンティティ(テーブルと同じようなもの?)を一つ配置します。ダイアログが出ると思います。ここは主キー(一意に識別するためのIDみたいなもの)と、エンティティに関する設定をします。多分そのままOKでいいような気がします…

 
 Entityへの要素(データ項目)の追加は、Entity上で右クリック→[新規追加]→[スカラー プロパティ]です。追加するとデフォルトでデータ型がStringになっているので、[プロパティ]ウィンドウの[全般]→[型]で適宜変更します。


 テーブル間のアソシエーション(SQLでのJOINのようなもの?)は、[ツールボックス]ウィンドウから[アソシエーション]を選択し、マウスでテーブル間をドラッグ&ドロップで繋ぐとできます。

 設計し終わったら、この論理モデル(≒設計図)から、実際にデータベース上に生成するための、SQL文を自動生成してもらいます。Entity Data Modelを設計するところの何も無いところを右クリック→[モデルからデータベースを生成]を選択します。
 

 最初のほうでプロジェクトに追加した、ローカルベースのデータベースファイルに接続することを確認します。そうしたら、次に行きます。



 DDLというタブに、論理モデルをデータベース上に生成するSQL文が書かれています。[完了]ボタンを押します。
 

 このSQL文を実行するには、左上の▷(右向き三角)マークの[実行]ボタンを押せば大丈夫です。しかし、接続文字列の問題からか、私の場合"database [Database1] does not exist. Make sure that the name is entered correctly."のようなエラーが出てしまい、実行出来ませんでした。どうやらSQL文の先頭の方にある、USE文でデータベースが選択できずにコケているようです。で、

ここで、このようなダイアログが出ることがあります。

 ローカルベースの場合(LocalDB)、この接続文字列には"(LocalDB)\11.0"などという文字列が入るものと思われます(参考:MSDN)。 の場面で右下のプロパティ欄に出ている接続文字列が、多分正しいものと思われますが、これをそのまま貼り付けると、文字数超過のようなエラーが出て接続出来ません。
 
 しょうが無いので、[サーバー エクスプローラー]→[*******.mdf]を右クリック→[新しいクエリ]を選択し、自動生成されたSQL文をそのままコピペして実行すると、同じようなエラーが出ますがなぜかテーブルは生成されています(なんでだ)。とりあえずできたので良しとはします…
コピペすると…
エラーが返ってくるが、なぜかテーブルは出来る…
これで一件落着、次はデータベースを操作することにします。長くなったので多分別の記事にします。

//書きかけ
Read more →

2013/04/30

[C#]Twitterizerでブロックしているか調べる、とか

,
 Twitterizerであるユーザーをブロックしているかどうか調べる、だけの話です(完全に覚書です)。

 コードはこんな感じになります。
private void blockToolStripMenuItem_Click(object sender, EventArgs e)
{
    //ブロックしているかどうか調べる
    const string screenName = "***********";
    var resp = TwitterBlock.Exists(token, screenName);
    if (resp.Result == RequestResult.Success)
    {
        //ブロックしている
        MessageBox.Show("yes");
    }
    else
    {
        //ブロックしていない
        MessageBox.Show("no");
    }
}

 TwitterResponse<TwitterUser>型で返ってきますが、ブロックしているかどうか、はTwitterResponse.ResultがSucceedならブロックしている/それ以外ならブロックしていない。となるみたいです。TwitterResponseにはRequestURLメンバがありますが、デバッグで見る限りは"http://api.twitter.com/1/blocks/exists.json?screen_name=[screenname]&include_entities=true"を取得してるみたいです。
 respにはTwitterUser型のUserメンバもあり、[screenName]さんのUser情報がそのまんま入ってました。

 ブロックしていない相手の場合、resp.ResultはFileNotFound、Contentは"{\"errors\":[{\"message\":\"Sorry, that page does not exist\",\"code\":34}]}"が返ってきてました。
ブロックしていないとき
で、ブロックしているユーザー一覧も取得できるはずなんですけど、次のコードだと何も返ってきません…

private async void ブロック一覧ToolStripMenuItem_Click(object sender, EventArgs e)
{
    var dialog = new ShowUsersDialog();
    dialog.Text = "ブロックしているユーザー一覧:";
    dialog.Show();
            
    var options = new BlockingOptions();

    await Task.Run(() =>
    {
        //ブロックしているユーザーのIDを取得する。
        //TwitterBlock.Blockingだとエラーが返ってくる
        var ids = TwitterBlock.BlockingIds(token);
        if (ids.Result == RequestResult.Success)
        {
            foreach (var u in ids.ResponseObject)
            {
                dialog.richTextBox1.Text += u + "\n";
            }
        }
        else
        {
            //取得出来ませんでした
            MessageBox.Show(ids.Result.ToString());
        }
                 
    });

}
実装されてない、とかなんですかね?OAuthとかjsonとかその辺りをC#で自分で処理できるようになりたいですね…

Read more →

2013/04/29

[C#]Twitterizerを使う

,
 Twitterizer(Twitterに関するライブラリ)を使ってみたお話です。と言うよりは、.NETのバージョンによるdllがホニャララな問題に苦戦した跡地です。

 動機は、某botが凍結され新垢が作られ、ふと、そういう一斉ブロックツールとか無いかなあ、と思ったことです。
 
 Twitterizerの使い方は簡単で、GitHubからZipをDLし、解答してできたフォルダのうち/Twitteizer2/Twitterizer2.csprojをビルド?すればobj/Debug/Twitterizer2.dllが作成されるので、それを参照に追加でとりあえずは使えました。(/Debug/Twitterizer2/Full/Twitterizer2.dllを使うべき?)
 VS2012で/Twitterizer.slnを開くと、一部(Twitterizer2.Async.SilverlightとTwitterizer2.Streaming.Silverlight)が使用不可と出るので、それを使った奴は知りません…
 StreamingAPIを使うためには、Twitterizer2.Streaming.dllを使う必要があります。また、Newtonsoft.Json.dllも必要です(GettingStarted.txtに書いてある)。

※2013/07/31追記 API 1.0は使えなくなりました。1.1に移行する必要があります。Twitterizerは開発が止まっているのか(GitHubよく読んでないからわからん)、有志の方による1.1に対応したdllを使う必要があります。随分古く何もない記事なんですけど、Twitterizerでググったら意外と上位に出てきてしまったので…書いておきます
 

 Twitterizerを使うにあたって、以下のサイトが参考になりました。

[C#] TwitterizerでスクリーンネームからTwitterのIDを取得する http://bit.ly/ZKGZ6P
Twitter タイムラインの取得、投稿 (C#) | 夏研ブログ http://bit.ly/ZKH76i
Twitterizerで特定ユーザーのフォロワーを取得する|Paco's style http://amba.to/ZKHaPw
Twitterizerメモ – 非同期処理 | サツキふぁくとりー http://bit.ly/ZKHfTc
Twitterizer で UserStream を取得する。 | みむらの手記手帳 http://bit.ly/ZKHhuo
C#でtwitterizerをつかってみた2 Twitterizerを使ったMyTwitterToolsクラス[.NET][C#][twitterizer][twitterAPI] - merusaiaのゲーム開発(奮闘)日記 http://bit.ly/ZKHkX6

 別にあとに残しておくほどのコードを書いてませんが、こんな感じで自分のIDなども取得出来ます。

/// <summary>
/// ユーザーのScreenNameやアイコンを、ラベル1,2に表示する
/// <summary>
/// <param name="token" />アクセストークン
private async void showUserProfile(OAuthTokens token)
{
    var r = TwitterAccount.VerifyCredentials(token);
    if (r.Result == RequestResult.Success)
    {
        label1.Text = r.ResponseObject.ScreenName;
        label2.Text = r.ResponseObject.Name;
        await Task.Run(() => pictureBox1.Load(r.ResponseObject.ProfileImageLocation));
        pictureBox1.Show();
    }
}

 で、最初既に存在していたdllを使ったところ、dllのバージョンの違い?によるエラーに悩まされました。エラーが出たのはTwitterUser.Show()を呼び出した時に発生した例外で、その内容は
ファイルまたはアセンブリ 'System.Windows, Version=2.0.5.0,Culture=neutral, PublicKeyToken=7cec85d7bea7798e'、またはその依存関係の 1つが読み込めませんでした。
といったもの。ググって出てきた解決策(UACに再登録すること。参考)してもエラーは直りませんでした。
こんなエラーが出ます…

 以下は私の考えですが、Versionが2.0なのは.NET Framework2.0用?で、試しに追加参照にSystem.Windows.dllで2.0のものを追加しても、ビルド時に下のようなエラーが出てしまう。競合してる模様。
"System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" と "System.Runtime.Serialization, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" の間の競合を解決する方法がありません。一時的に、"System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" を選択します。

 で、結局Twitterizer2を自分でビルドしたらエラーは直りました。

苦戦した跡
こんな感じになってた

 一時期Twitterizer2ではなくTweetSharpにしようとしましたが、どうにもAPIリファレンスも見つからず、あまりにも資料を見つけられなかったので投げました。まず、OAuth認証するときにPINコード入力するようにするのが不明(TwitterDevelopmentでアプリケーションがWebなのかClientなのか指定できなくなっている?)なので…

 パッケージの復元は既定で無効になっています。確認のため、Visual Studio の [オプション] ダイアログ ボックスを開き、Package Manager ノードをクリックして、[NuGet がビルド中に存在しないパッケージをダウンロードするのを許可する] チェック ボ…
というエラーが出た場合は、VS2012だと何故か[Package Manager]が無いので、手動でNuGetフォルダをコピーした記憶があります。
 
 呟くまで、は c# - How to get the Twitter Usertimeline with Tweetsharp - Stack Overflow http://bit.ly/11rnIEe とかが参考になりました。
Read more →

2013/01/13

[C#]Vista風ダイアログを表示したい

,
 C#のFolderBrowserDialogなどを自分はよく使うんですが、如何せんちょっとデザインが古い。XP-likeである。俺はVistaみたいなのがいいんだ~~~~、ということで、Vista風のダイアログを使えるようになるライブラリの紹介。
Ookii.Dialogs - ookii.org
Vista Controls - CodeProject
とか。使ったことはない。
 ライブラリ入れなくてもVista風にできるのかな?それはよく知らないや…
 
 (FolderBrowserDialogは)継承元がCommonDialogですし、UI Editorが優秀だしカスタマイズしやすいのがいいですね。おしまい。
Read more →

[C#]アプリケーションが UserInteractive モードで実行されていないときに、モーダル ダイアログまたはフォームを表示することは有効な操作ではありません。

,
 えっと、タスクスケジューラで自分で書いたWindowsフォームアプリケーションを起動しようとして、なんか詰まった点2つの話です。

1)タスクスケジューラがエラーを返す

 毎日0800に.exeを起動するようにタスクスケジューラに登録して、次の日確認してみたら案の定動いてませんでした。翌日、その次の日も結局動かずで。タスクスケジューラの管理画面を見ると、どうやら2147750692というエラーで止まっているようです(下の写真参照)。
こんなエラーが出ました

 ネットで調べてみると、2147750692というエラーコードは

The Task Scheduler service attempted to run the task, but the task did not run due to one of the constraints in the task definition. 

とのこと。はあ、つまり何らかの理由で動かんかったよ、と。原因が絞れないですね…
 とりあえず、「タスクスケジューラ」手動でタスクをスケジュールする方法<Windows Vista(R)>: dynabook.comサポート情報を参考にして、タスクの設定を変えてみます。結局動かずじまいでした。


2)テストしたら'System.InvalidOperationException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました。って出た

 で、タスクスケジューラは試しにその場でタスクを実行できるので、やってみたところ「デバッガを起動しますか?」とダイアログが出たので、VS2008を起動してみたら上記の例外が発生していたみたいです。
こんな感じで、タスク上を右クリックで[実行する]メニューが出てくる~~~~
 
上記の例外の全文は
'System.InvalidOperationException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました。

アプリケーションが UserInteractive モードで実行されていないときに、モーダル ダイアログまたはフォームを表示することは有効な操作ではありません。サービス アプリケーションからの通知を表示するには、ServiceNotification または DefaultDesktopOnly スタイルを指定してください

です。要はタスクスケジューラから起動するときはフォームとかMessageBox使わないでねってことなんですかね…"UserInteractiveモード(ユーザ対話モード)"の定義がなかなか見つかりませんでして…

 で、そうなるとプログラムを修正しないといけなくて、実はUserInteractiveモードか否かは
boolean IsUserInteractive = Environment.UserInteractive;
というコードで取得できるみたいなので、
[STAThread]
static void Main(string[] args)
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    if (Environment.UserInteractive)
    {
        //UserInteractiveモードなので表示
        Application.Run(new Form1());
    }
    else
    {
        //UserInteractiveモードじゃないときは、ここでUIを使わないコードをごにょごにょ
    }
}

というコード書いて、Main()でFormを表示する前に分岐させてみました。というお話。動いてくれるといいな…(動作確認してない)
Read more →

2013/01/08

[C#]Google Driveに新しいディレクトリを作る

,
 Google APIs Client Library for .NETで遊んでみました。このライブラリは、色々な言語のものが用意されてますね、びっくりです。後あまり他にやってる人を見ないので、日本語のページが少なくて辛いです…

 で、まずはGoogle Driveにファイルをアップロードする(Google先生曰くこれがHello, World!らしい)ところから始めます。Google Drive SDK — Google DevelopersのQuickstart: Run a Drive App in Javaを見てやってみましょう。という話。

フォルダはどうやって表されているの?

とりあえずQuickstartは動いたので、次にフォルダを作ってみます。Google Driveでフォルダはどうやって表されてるの?ということで、貴重な日本語公式資料のファイルとフォルダを操作する - Google デベロッパー アカデミー — Google Developersによると、『フォルダとは、MIME タイプが application/vnd.google-apps.folder で、拡張子を持たないファイルです。』らしいです。

 えっ………ファイル………………?


とりあえずフォルダを作ってみる

※以下Quickstartのコードのファイルアップロードするところだけをちょこまかといじってます。認証部とかはそのままにしてます。

 見なかったことにしてネットの海でコードを探します。c# - upload an Image to a created folder in Google drive account - Stack Overflowを見るところによれば、ファイルを作る場合、Quickstartにも似たようなコードが出てきたように、Fileクラスのインスタンスは
     
//ファイルのひな形を作る感じ
File body = new File();
body.Title = "My document";
body.Description = "A test document";
body.MimeType = "text/plain";

//ファイルの中身を書き込む…?
byte[] byteArray = System.IO.File.ReadAllBytes("document.txt");
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);

//アップロードする
FilesResource.InsertMediaUpload request = 
service.Files.Insert(body, stream, "text/plain");
request.Upload();

//アップロードされたファイルのIdを取得しておく
File file = request.ResponseBody;
Console.WriteLine("File id: " + file.Id);

のように設定してアップロードします。ですが、フォルダを作成する場合には、
            
//フォルダを作る
File folder = new File();
folder.Title = "myfolder2";
folder.Description = "my folder description";
//フォルダなのでMimeTypeはこれ
folder.MimeType = "application/vnd.google-apps.folder";

//アップロード
File file = service.Files.Insert(folder).Fetch();
Console.WriteLine("folder id : " + file.Id);

という風にすると、フォルダが作成できるみたいです。ちゃんとMime Typeがapplication/vnd.google-apps.folderになってますね。

 アップロードの手順も違っていますが、何か意味があるんでしょうか…(動いたからとりあえず違いに目を瞑っている)

動きました
ま、とにかくこれでフォルダが作れることがわかりました。


親フォルダを指定してファイルをアップロードする


 はてさて。親フォルダを指定する場合はどうすればいいんでしょう?上に紹介したリンク先のコードにある通り、
string parentId = "";//親フォルダのId
File file = new File();
//...
file.Parents = new List<parentreference>()
   { new ParentReference() {Id = parentId} };

とします。ですが親フォルダのIdが分からないので、フォルダを検索してIdを取得してこないといけません。検索はどうやってするんだ…?

 Search for Files Google Drive SDK — Google Developersより、Files.listを使えばいいらしいので、Files: list - Google Drive SDK — Google Developersのサンプルコードを実行してみます。
 ここでは、フォルダだけを表示するために、Query = "mimeType = 'application/vnd.google-apps.folder'"としています。クエリの詳細は上のSearch for Filesを見てください。便利ですねこれ。
//フォルダのみを選ぶクエリ
string query = "mimeType = 'application/vnd.google-apps.folder'";
List<file> result = new List<file>();
FilesResource.ListRequest req = service.Files.List();
req.Q = query; //クエリを使わない(全ファイル、フォルダを表示)時は削除

do
{
      try
      {
            FileList files = req.Fetch();
            result.AddRange(files.Items);
            req.PageToken = files.NextPageToken;
       }
       catch (Exception e)
       {
            Console.WriteLine("An error occurred:" + e.Message);
            req.PageToken = null;
        }
 } while (!String.IsNullOrEmpty(req.PageToken));
            
 //検索結果を見てみよう
foreach (File f in result)
{
       Console.WriteLine("File name :" + f.Title + " id :" + f.Id);
}

 すると、コンソールにフォルダ名とIdが出てきたと思います。これで準備は整いましたね。さっき作ったmyfolder2にdocument.txtをアップロードする場合は、

//まずフォルダ名がmyfolder2なものを検索
string query = "title = 'myfolder2'";
List<File> result = new List<File>();
FilesResource.ListRequest req = service.Files.List();
req.Q = query;

do
{
      try
      {
            FileList files = req.Fetch();
            result.AddRange(files.Items);
            req.PageToken = files.NextPageToken;
       }
       catch (Exception e)
       {
            Console.WriteLine("An error occurred:" + e.Message);
            req.PageToken = null;
        }
 } while (!String.IsNullOrEmpty(req.PageToken));

//親フォルダのIdをコピっとく
string parentId = "";
foreach (File f in result)
{
    parentId = f.Id;
}

//ファイルをアップロードします
File body = new File();
body.Title = "My document";
body.Description = "A test document";
body.MimeType = "text/plain";
body.Parents = new List<ParentReference>(){
    new ParentReference() { Id = parentId } 
};

byte[] byteArray = System.IO.File.ReadAllBytes("document.txt");
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);

FilesResource.InsertMediaUpload request =
        service.Files.Insert(body, stream, "text/plain");
request.Upload();

File file = request.ResponseBody;
Console.WriteLine("File id: " + file.Id);
Console.WriteLine("Press Enter to end this process.");
Console.ReadLine();
とすればいいみたいです(エラー処理はしてないので各自で)。めでたしめでたし。

 3日前くらいにつまったのですが、なんとか解決したので良かったです。しかし、いちいちAuthorization Codeをコピペするのは面倒なんですが…ココらへんを参考にして、どうにかしたいですね。
 後、記事が無駄に長くなっちゃって、もう少し見栄え良く読みやすい記事を書けないものかと思います…

おまけ


 SyntaxHighlighterで<や>を使う場合には、HTML Escapeしないといけないんですね。<なら&lt;に。>なら&gt;に。です。
 
 まあBloggerの場合は、コードをHTML編集で貼り付けると、InvalidなHTMLは認めないらしくてList<File>と書くと勝手に</File>してくれます。凄い…凄いけどいらない…
Read more →

2012/07/11

[プログラミング]iTextSharpでpdfを操作する

,
pdfはめんどくさい pdfはしねばいい pdfは云々、とpdfに関する恨みを並べても、結局使わないといけないのは変わらないので…諦めて向き合います

http://homepage2.nifty.com/nonnon/SoftSample/CS.NET/SamplePdfSplit.html
http://jp.techerald.com/page/imagen-itextsharp-mantener-las-dimensiones-en-pixeles.html
http://stackoverflow.com/questions/4932187/itextsharp-scaling-image-to-be-full-page
http://yonaizumi.dip.jp/weblog/cappe/2010/11/ctiffpdf.html
http://sourceforge.net/projects/itextsharp/

参照の設定は、dllをどっかに保存しといて、参照の追加→参照→dllを指定
コンパイルすると、なんか自動的に/Debug、/Release に配置される???

なんか、AbsolutePositionって左下が(0,0)なのかな。直さなきゃ

コード(適当)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
//iTextSharp
using iTextSharp.text;
using iTextSharp.text.pdf;

namespace jpg2pdf
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        //jpgファイルを開く
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();

            ofd.FileName = "default.jpg";
            ofd.InitialDirectory = "";
            ofd.Filter = "jpgファイル(*.jpg)|*.jpg|すべてのファイル(*.*)|*.*";
            ofd.FilterIndex = 1;
            ofd.Title = "開くファイルを選択してください";
            ofd.RestoreDirectory = true;
            ofd.CheckFileExists = true;
            ofd.CheckPathExists = true;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = ofd.FileName;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            var sfd = new SaveFileDialog();

            sfd.FileName = "無題.pdf";
            sfd.InitialDirectory = "";
            sfd.Filter = "pdfファイル(*.pdf)|*.pdf|すべてのファイル(*.*)|*.*";
            sfd.FilterIndex = 1;
            sfd.Title = "保存先を指定してください";
            sfd.RestoreDirectory = true;
            sfd.OverwritePrompt = true;
            sfd.CheckPathExists = true;

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                textBox2.Text = sfd.FileName;
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            var doc = new Document();
            //pdf保存先
            PdfWriter.GetInstance(doc, new FileStream(textBox2.Text, FileMode.Create));
            //pdfを開く
            doc.Open();
            //画像データを取得
            var image = iTextSharp.text.Image.GetInstance(textBox1.Text);
            doc.SetPageSize(PageSize.A4);
            //サイズのフィット
            image.ScaleToFit(doc.PageSize.Width, doc.PageSize.Height);
            //画像の配置箇所設定
            image.SetAbsolutePosition(0f, 0f);
            //用紙サイズの設定
            //doc.SetPageSize(new iTextSharp.text.Rectangle(image.PlainWidth, image.PlainHeight));
            //書き込み
            doc.Add(image);
            //pdfを閉じる
            doc.Close();
            //完了のダイアログ(無いと終わったかわからない)
            MessageBox.Show("変換が完了しました");
        }

    }
}

Read more →