2017年2月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28        

Amazonウィジェット

  • miniPC
  • 最近買った本
  • Raspberry Pi
  • クアッドコプター
  • 書籍ランキング

AdSense

  • 広告
無料ブログはココログ

« 2016年10月 | トップページ | 2016年12月 »

2016年11月

2016年11月27日 (日)

C言語 CSVを読み込む関数をsscanfとstrchrで作ってみた。

CSVを読み取る機会は多いものの、C言語の入門本やWebにはなかなかそういうのが書いていなくて、学習の最初のほうは難儀しました。たしか最初に作ったアプリは単語帳ソフトで、CSVで保存しようとしていたのですが、どうにも動作が安定せず挫折したような記憶があります。最初から文字列処理が得意なperlないしはpythonでも使っていればもう少し簡単だったのかもしれませんが。

今までにもC言語で色々な方法でCSVを読み取る関数を作ってきましたが、今回はsscanfを使って作ってみました。


とりあえずべた書きで処理を書いてみた。

#include 

char str[] = "1,2,3,4,5,6,7,8";

void main(void){
       char *adr;
       adr = str;
       for (int i = 0; i < 10; i++){
              int res;
              int col;

              res = sscanf(adr, "%d", &col);
              if (res < 1 || res == EOF){
                     continue;
              }
              printf("%d\n", col);
              adr = strchr(adr, (int)',');
              if (adr == NULL){
                     continue;
              }
              else{
                     adr += 1;
              }
       }
}


関数にまとめてみた。

#include 

char str[] = "1,2,3,4,5,6,7,8";


//戻り値:読み取りに成功=0,取りこぼし=-1
//引数:読み取り対象文字列、読み取り値を入れる配列、読み取り要素数
int csvIntRead(const char *str, int *col, const int num){
	char *adr;

	int succNum = 0; //読み取り成功カウンタ

	//開始位置をセット
	adr = str;

	for (int i = 0; i < num; i++){
		int res;

		//数字を読み取る
		res = sscanf(adr, "%d", &col[i]);
		if (res < 1 || res == EOF){
			//読み取れなかったら終了
			break;
		}
		else{
			//読み取り成功回数をカウント
			succNum++;
		}
		
		//次のカンマを探す
		adr = strchr(adr, (int)',');
		if (adr == NULL){
			//見つからなかったら終了
			break;
		}
		else{
			//カンマがあればその次の文字を開始位置にセット。
			adr += 1;
		}
	}

	if (succNum == num){
		//指定した読み取り数と等しければ成功
		return 0;
	}
	else{
		//どこか取りこぼしがあった場合
		return -1;
	}
}


void main(void){

	int dat[8];

	int res = csvIntRead(str, dat, 2);
	for (int i = 0; i < sizeof(dat)/sizeof(int); i++){
		printf("%d\n",dat[i]);
	}
	printf("\n");

}

2016年11月20日 (日)

python小技 map関数の小技

map関数を使うと、リストの各要素に対して同じ操作を行うことができます。
もっともよく使いそうなのは、CSVから数字を読んでその内容を処理したいとき。
for文で一個ずつint関数に突っ込んでもいいのですけど、内包表記とかmap関数を使うと下記のようにコンパクトに書けます。

たとえばファイルからCSVを一行読み込んだ、こんなリストaがあるとする。
a = ['12','13','14','15','16']

数値の左右にシングルクォーテーションがあるのは、ファイルから数字を読み取ったままだと文字列があるから。それをintに直したいとしたら、直した結果をnに入れていくようにして

n = [ ]
for t in a:
  n.append(int(t))
というようなことを書くこともできるが、map関数を使えば

map(int, a)
とすることもできる。
これは、第一引数が処理関数の指定。第二引数がリストで、リストの要素一個ずつを処理関数に渡してリストの内容を更新していくということ。
C言語で言うところの関数へのポインタを使っているのに近い。

map関数に加えて、lambda式を使えたらこんなこともできる。

map(lambda x: chr(x), range(0x30,0x30+10))
これは、
0x30から10個分のintのリスト要素それぞれを、ASCII文字に変換する。

処理した結果はこうなる。
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

ASCIIで0x30は数字の0という文字になるので、1個目が0で9まで続いている。

lambda x
というのがラムダ式というもので、引数xをとるlambdaという名前の関数があると考えればうまくいく。HPからコピペするだけだったり、丸覚えしようとするとうまくいかなかった。

確かタプルのリストを作ってそれをsort関数でソートしようとしたときに覚えて、
それから手になじむようになった。使い道が無いのに覚えようとすると、これはなかなかに難しい。


2016年11月13日 (日)

C# イベントを発生させる方法

イベントを発生させる方法。
別スレッドに処理をさせている間に、なにか問題があったときに報告させたり、グラフィックの再描画が必要なタイミングをイベントから知るようにするときに使う。
コンソールアプリで実行できる簡単な例を記載。

メインループでは最初にYobidashiというクラスのインスタンスを作ってstartメソッドを呼び出す。あとはreadlineで入力待ちのため何もしない。

Yobidashiのstartでは、SleepClassが作られて、SleepClassの持つイベントにイベントハンドラが登録される。SleepClassのオブジェクトがStartを呼んだあとは、Startメソッドのなかで3秒間待つ。3秒たったらTime(this,EventArgs.Empty)が実行されて、ここでイベントが発行される。

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

namespace CS_eventTameshi
{
    class Program
    {
        static void Main(string[] args)
        {
            Yobidashi y = new Yobidashi();
            y.start();

            Console.ReadLine();
        }
    }

    class Yobidashi
    {
        public void start()
        {
            SleepClass clsSleep = new SleepClass();

            //イベントハンドラの追加
            clsSleep.Time += new EventHandler(this.SleepClass_Time);
            clsSleep.Start();
        }

        private void SleepClass_Time(object sender, System.EventArgs e)
        {
            //起動してから3秒後におkが表示される。エンター押すと終了
            Console.WriteLine("ok!");
        }
    }
    

    class SleepClass
    {
        public event EventHandler Time;

        public void Start()
        {
            System.Threading.Thread.Sleep(3000);
            if (Time != null)
            {
                Time(this, EventArgs.Empty);
            }
        }

        
    }
}

<自分の勝手な理解>
イベントにイベントハンドラをセットするのは、 C言語で言うところの、関数ポインタをセットしておくのに似ている。

+=という操作をすると、そこで指定した関数へのポインタがセットされる。 イベントを発生させる側で、イベントの関数を実行すると、 その中にセットされていたイベントハンドラへのポインタがロードされて、 今度はそれが実行されるようになる。

そのために、例示したソースの中で
if (Time != null)

というのがあるが、これはeventに何も入っていなければそこへ飛びようがないので、 中身がなければ処理しないということ。

2016年11月 6日 (日)

C# 図形の塗りつぶし色の変え方

C# Csharp グラフィック 塗りつぶし四角形の色の変え方。システム色以外のRGBによる設定

MSDNのドキュメントはどれもすさまじい日本語で、英語の原文を読んだほうがよほどましな気がした。キーワード検索すると必ず日本語のページが出てくるので、最後にenglishを入れて検索する。

Rectangle構造体 これはあくまでも構造体のようで、描画をするためのものではない。
サイズを指定するようなもの
https://msdn.microsoft.com/ja-jp/library/system.drawing.rectangle(v=vs.110).aspx

上のページから、備考の欄にFillRectangleメソッドへのリンクが貼ってある。
https://msdn.microsoft.com/ja-jp/library/yysstebh(v=vs.110).aspx

このページの構文のところで
BrushとRectangleを引数として受け取るということがわかる。

Brushのリンクを辿ると、
https://msdn.microsoft.com/ja-jp/library/system.drawing.brush(v=vs.110).aspx
四角形、楕円、扇形、多角形、およびパスなどのグラフィカル形状の内部を塗りつぶすに使用されるオブジェクトを定義します。
とあるが、abstractがついているのでこのままではオブジェクトを作れない。
このクラスを継承しているクラスが他にあるということ。

解説のところに、
これは抽象基本クラスであり、インスタンス化することはできません。 Brush オブジェクトを作成するから派生したクラスを使用して Brush, など SolidBrush, 、TextureBrush, 、および LinearGradientBrushです。
ということが書かれているので、SolidBrushのリンクを辿ってみた。

すると、ようやくやりたいことが見えてきた。
https://msdn.microsoft.com/ja-jp/library/system.drawing.solidbrush(v=vs.110).aspx

この中の例をみると、
Color customColor = Color.FromArgb(50, Color.Gray);
SolidBrush shadowBrush = new SolidBrush(customColor);

となっていたので、
Color.FromArgb
とVisualStudio内で打ち込んでみて、Intelisenseで表示される、
RGBをint値でそれぞれ指定するメソッドを選べばいいことがわかった。

最終的にコードはこんな風になった。

SolidBrush brush = new SolidBrush(Color.FromArgb(150,0,30));
g.FillRectangle(brush, 0,0,100,100);

SolidBrushにColorを渡してまずはブラシをつくり、
それを図形を描画するメソッドに渡せば、その色で塗りつぶしが実行できるということ。

« 2016年10月 | トップページ | 2016年12月 »