読者です 読者をやめる 読者になる 読者になる

プログラミング素人のArduino

技術屋の末端。プログラミングは専門外。 電気回路も専門外です。 コードに間違いなど見つけられたら、気軽にコメントください。 VC#始めました。

C#でウェブスクレイピング

今回はウェブスクレイピングをやってみます。
↓の続きになります。
s51517765.hatenadiary.jp

ウェブスクレイピングとして、Webの情報を取得する基本的な構文は↓を参考にしました。
www.casleyconsulting.co.jp

Visual Studio上でクラスファイルを追加して、ウェブスクレイピングのコードを作成します。
f:id:s51517765:20170505154304j:plain

これは、URLを指定するとそのページのHTMLをstring型の文字列として取得します。
この内容は、あまり深く考えずにこういう一つのメソッドとして理解しておけばとりあえずいいと思います。

        public string Gethtml(string url)
        {
            // 指定されたURLに対してのRequestを作成します。
            var req = (HttpWebRequest)WebRequest.Create(url);     //using System.Net;

            // html取得文字列
            string html;

            // 指定したURLに対してReqestを投げてResponseを取得します。
            using (var res = (HttpWebResponse)req.GetResponse())
            using (var resSt = res.GetResponseStream())
            // 取得した文字列をUTF8でエンコードします。
            using (var sr = new StreamReader(resSt, Encoding.UTF8))     //using System.IO;
            {
                // HTMLを取得する。
                html = sr.ReadToEnd();
            }

            return html;
        }

このとき、System.NetとSystem.IOを使いますので、以下をファイルの先頭に追加しておきます。

using System.Net;
using System.IO;

つぎに、同じクラスファイル上にキーワードを抽出するプログラムを作成します。
引数としては先ほどのメソッドで取得したHTMLとキーワードを指定します。
考え方としては、Keywordを含む文を<P></P>で囲まれる部分で区切り取得します。
f:id:s51517765:20170506121935j:plain

①まずHTML全体の中からKeywordをさがす。html.IndexOf(Keyword)構文でhtmlのなかでKeywordの位置を探します。
Substring(start,Length)構文で、start =0(最初)から前記Keyword位置までを取得。
②前記Keywordよりまえの部分の中から後ろからさがして<p>を探す。
ここでは、Keywordから前へひとつづつ文字を追加して<p>をさがし、見つかったらこれがほしいKeywordより前の部分になります。

for (int n = 1; n <= buf_buf_mae.Length; n++)
            {
                buf_mae = buf_buf_mae.Substring((buf_buf_mae.Length) - n, n);

③~⑤後ろは同様に</p>を探します。
これを足し合わせるとKeywordを含む文が取得できます。

string getWord = buf_mae + buf_ushiro;

これをまとめると、Keywordの取得メソッド

        public string GetKeyword(string html, string Keyword)
        {
        header = "<p"
        footer = "</p"

            // html文字列内からKeywordをさがしその位置を返す
            int keywordStart = html.IndexOf(Keyword);

            string buf_buf_mae = html.Substring(0, keywordStart);
            string buf_mae = "";
            for (int n = 1; n <= buf_buf_mae.Length; n++)
            {
                buf_mae = buf_buf_mae.Substring((buf_buf_mae.Length) - n, n);
                if (buf_mae.IndexOf(header) > 0)
                {  //後ろからさがして見つかったら
                    break;
                }
                if (n > 5000)
                {
                    MessageBox.Show("Header get Error.");
                    break;
                }
            }

            string buf_ushiro = html.Substring(keywordStart); //indexOfから後ろを取得第2引数省略
            int nagasa_u = buf_ushiro.IndexOf(footer);
            buf_ushiro = html.Substring(keywordStart, nagasa_u + 4); //start位置,対象文字列長さ

            string getWord = buf_mae + buf_ushiro;
            return getWord;

        }

次にForm1にHTMLのボタンクリックイベントを作成します。

     private void buttonGethtml_Click(object sender, EventArgs e)
        {
            ViewBoxBackColorSet();

            if (checkBoxWriteOut.Checked == false && checkBoxPreview.Checked == false)
            {
                MessageBox.Show("Select output");
            }
            else
            {
                DateTime dt = DateTime.Now;
                string date = dt.ToString("yyyy_MM_dd_HH_mm_ss");
                try
                {
                    textBoxPreview.AppendText(dt.ToString("HH:mm:ss" + Environment.NewLine));

                    var scr = new Scraping();  //クラスScrapingを使うためにインスタンス作成
                    string url = textBoxURL.Text;
                    string html = scr.Gethtml(url);

                      Keyword = comboBoxKeyword.Text;
                    
                    string getWord;
                    getWord = scr.GetKeyword(html, Keyword);
                    if (checkBoxPreview.Checked == true)
                    {
                        textBoxPreview.AppendText(getWord + Environment.NewLine);
                    }
                    if (checkBoxWriteOut.Checked == true)
                    {
                        using (StreamWriter writer = new StreamWriter("H_" + date + ".txt", true))
                        {
                            writer.Write(getWord);
                        }
                    }

                }
                catch
                {
                    MessageBox.Show("Check URL");
                }
                ViewBoxBackColorReset();
            }
        }

このへんがオブジェクト指向(クラス設計)っぽいところ。
クラスを使うためにインスタンスの宣言をして、入力(ここではURL)と出力(ここではHTML)(および、HTMLとKeywordとWord)だけが見えている状態になります。

 var scr = new Scraping();  //クラスScrapingを使うためにインスタンス作成
 string url = textBoxURL.Text;
 string html = scr.Gethtml(url);

 string getWord;
 getWord = scr.GetKeyword(html, Keyword);

これで、必要部分は取得できましたが、HTMLのタグが不要です。
f:id:s51517765:20170506123724j:plain

  public string deleteTag(string getWord)
        {
            int buf_int = -1;
            int buf_int2;
            string tukau1, tukau2;
            string buf_1;
            string deleteTag_getword;

            for (int n = 1; n < 80; n++)
            {
                buf_int = getWord.IndexOf("<");
                if (buf_int < 0)
                {
                    break;
                }

                tukau1 = getWord.Substring(0, buf_int);
                buf_1 = getWord.Substring(buf_int + 1);
                buf_int2 = buf_1.IndexOf(">");
                tukau2 = buf_1.Substring(buf_int2 + 1);

                getWord = tukau1 + tukau2;
              
            }
            deleteTag_getword = getWord;
                 return deleteTag_getword;
        }

このように<>で囲まれた部分をHTML Tagとみなして削除するメソッドを入れると、すっきりします。
タグのスタート<を探し、これ以前の文字列を取得し、<の次の文字から>を探しこれをタグとみなして捨てる。>の次の文字から同じようにタグを探し、文字列を取得し最初に取得したタグの外とつなげて…という風にしていきます。
forの構文の繰り返し数は適当にいれていますが、タグが見つからなくなったら、IndexOf = -1となるので、こうなったらBreak;で終了。

bufはbufferの略であまり綺麗とは言えないがよく使われる一時的な変数のことです。

f:id:s51517765:20170506125852j:plain

※HTMLのタグは「半角<>」を使いますが、ブログ上で半角<>を使うタグとみなされて表示されないので、全角<>を使っています。

C#でTwitterにつぶやく

このページを参考にC#からTwitterにつぶやいてみたいと思います。
blog.clock-up.jp

パッケージマネージャーコンソールから、ライブラリを導入します。
パッケージマネージャーコンソールは下の図のように開きます。
f:id:s51517765:20170507134201j:plain
すると、↓のようなコンソールが開くので、
f:id:s51517765:20170507134301j:plain

Install-Package CoreTweet

と入力します。

次にAPIキーを入手します。
twiiterアカウントに電話番号の登録が必要になります。
apps.twitter.com

ライブラリの登録をして、

using CoreTweet;
using System.Diagnostics;

ボタンクリックイベントを作ります。
最終的にはPincode入力用のFormを作りますが、今は簡易的にMessageBoxを出して、
その間に、Twiiterの認証画面を通過して、直接プログラムを書き換えてPincodeを通しています。
なんか、あらかじめブラウザでTwiiterにLogInしていないと、通らない???

 private void button1_Click(object sender, EventArgs e)
        {
            var session = OAuth.Authorize("*********", "*********");
                          //("入手した api_key", "入手した api_secret");
            Process.Start(session.AuthorizeUri.AbsoluteUri);

            MessageBoxShow("Get Pincode.");  //ここでPincodeの入力待ち

            var pincode"123234545676";   //ここを書き換える

            //トークン取得
            var tokens = OAuth.GetTokens(session, pincode);

            try
            {
                tokens.Statuses.Update(status => "hogehoge");
            }
            catch 
            {
                MessageBox.Show("Error");
            }

        }

で、APIは通ったようでプログラムはErrorがないのにタイムラインにつぶやきが更新されないのはなぜ???

<5/9更新>
APIAccess LevelがReadになっていて、Write権限がなかったため、書き込みができなかったらしい。
Read and writeに設定したはずだが、画面上ではRead and writeと出ていても、Read Onlyになっていることがあるようだ。
一度 Read, Write and Access direct messagesに変更して保存し、Read and writeに戻したら有効になった。
f:id:s51517765:20170509213451j:plain
<5/25更新>
APIが通っても一度しかTweetが成功しないことが続いた。数時間経過後に再びTweetができるのだが、どうやら同じ内容を連続してTweetしようとすると、Twitter側から弾かれるらしい。

「人工知能は人間を超えるか」を読んで

人工知能(Artificial Intelligence; AI)、ディープラーニング機械学習といった言葉が話題だ。
世の中すべてが人工知能に置き換えられるような勢いだ。
そうなってしまったら、人間の価値はどこにあるのだろうか?

この本は比較的わかりやすい例を用いて数式がほとんど出てくることなく、人工知能の過去と未来についてわかりやすく書かれている。

機械学習とは人工知能に知能を授ける方法のひとつで、ディープラーニング機械学習の一つである。
またニューラルネットワーク機械学習のための方法のひとつである。
f:id:s51517765:20170505113319p:plain

人工知能、機械学習、ディープラーニングの違いとは | NVIDIA



人口知能はまだ完成していない。
それどころかできてさえいない、というのが専門家の認識らしい。

そういわれると、「人口知能すでにあるよね」と思う人も多いかと思う。
人工知能の定義にもよるが、目指すべき人工知能とは

「サンプルとなるデータをもとに自らルールや知識を学習するもの」であるからだ。

人工知能という言葉自体は1960年代からあるが、「単純なプログラムを人工知能と呼んでいるだけのもの」、「入力と出力の組み合わせの数が極端に多いもの」、これらが人口知能と呼ばれているからである。
たとえば前者は、スイッチが押されたら過熱を始め、一定時間が経過したら、温度を下げて…といったことを行う炊飯器のようなもの、後者はAlphaGo(アルファ碁)のようなもの。
AlphaGoは言ってみれば無数の手をGPUによって力任せにシミュレーションし、勝つ確率が最も高い手を見つけ出しているに過ぎない。

機械翻訳がここ数年飛躍的に進歩して英語を勉強する必要のない日もそう遠くないと思い始めているのだが、今あるものはロジックを知ってしまうと、これも人工知能といえるものではないし、もう少しかかりそうに思える。

人工知能が ”躓いている” 課題が「抽象化」である。
「特徴」を抽出することであるが、目が二つあって耳が三角で髭があるのが「猫」だよ、ということを習得すれば、三毛猫もアメリカンショートヘアも「猫」であるという概念が形成されるが、これまでコンピューターは1番目のドットが茶で二番目のドットが黒で3番目の…が「猫」だと学習していたのでは、黒猫は猫と認識することはできない。

人工知能が普及したころには、なくなる職業、なくならない職業というのはよく言われるが、情報の価値がインフレ化していくのではないかと思う。今と同じような考え方では当然通用しなくなるが、アナログな仕事は無くならないとも思う。

C# でテキストファイルスクレイピング

ウェブスクレイピングという言葉がありますが、これはウェブ(特定のHP上)から必要な情報を取り出すものです。
www.fascinatedwithtofu.com

仕事(電子機器開発)上で機械の動作ログがテキストで出てくるのですが、これを解析するのに通常はExcelのマクロで行っています。
機能としては十分なことが可能なのですが、実行速度が遅い。

ここで、これをC#で作ってみようと思いました。
StreamReaderをつかえばできそうなことは容易に想像がつきます。
結果的にはExcel VBAより高速に抽出が完了します。
また、VBAの場合はファイルの読み込み中に他のExcelでの作業ができませんが(できなくもないけど)C#で作れば、Excelのプロセスが使われるわけではないのでExcelの作業を止めることもありません。

UIとしては↓のようなものを作成し、「Target / URL」ボックスは今後作るウェブスクレイピング向け。
Kyewordに目的のIndexを入れて「File」クリックで実行します。
f:id:s51517765:20170430122815j:plain

<命名ルール>
デザイナーは敢えて公開しませんが、
ボタンクリックイベントは
「ボタン名_Click」 →ex) private void FileOpen_Click …
チェックボックスの状態はチェックボックスのDefaolt名がcheckBox(Number)だと思うので、checkBoxという名前を残して、
「checkBox名称」 → ex) checkBoxPreview
コンボボックスなら「comboBox名称」→ ex) comboBoxKeyword
というようにつけていくと後々わかりやすいのではないかと思います。
もっといい方法(きちんとした命名ルール)があるかもしれなくて、自作の方法ですが。

<機能>
・テキストまたはそれに準ずるファイルを読み込むことができる。
・Keywordが含まれている「行」を抽出しTextファイルに出力する。
・Previewボックスに出すこともできる。
・上記2つの出力先はチェックボックスで切り替え可能。
・上記チェックボックスがいずれもチェックされていないときはErrorをだす。
・読み込み中は読み込みが実行中であることを示す。(今回はPreviewボックスのグレーアウトと、ボタンの無効化)
・Previewボックスには読み込みが続けて行われても、区別できるようにする(今回は読み込み開始時刻をいれる)
・使用許諾に了承しない人には使わせない

<ロジック設計>
プログラムを実行するにはそのプログラムが正しく動作する条件が必要です。
まず捜索するKeywordが必要です。これがないときは基本的にはErrorです。
しかし、「Blank」というのもありといえばあり。
出力条件はそのプログラムの実行結果の出力なので、これがないとなにも意味を成しません。
この条件判断はなくてもErrorが出るわけではありませんが、その他のErrorがあるのか、本当に動作した結果何も出力がないのか、の判断がつかないのは困るので入れておくほうがいいと考えられます。
f:id:s51517765:20170430132003j:plain

<実行結果>
テスト用の題材としてはWikipediaのあるページのHTMLソースをテキストに保存したものを使いました。
例えば、"<h" をKeywordにすると、<h1、<h2、<h3…などの含まれた行だけを取り出すことができます。
f:id:s51517765:20170430182103j:plain

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Collections;

namespace mojiretsu
{
    public partial class Form1 : System.Windows.Forms.Form
    {

        private void Form1_Load(object sender, EventArgs e)
        {

            Boolean UserSet = false;
            var listKeyword = "";
            try
            {
                StreamReader srKeyword = new StreamReader("ListKeyword.txt");
                while ((listKeyword = srKeyword.ReadLine()) != null)      // ストリームの末尾まで繰り返す
                {
                    if (listKeyword != "123456789012")
                    {
                        comboBoxKeyword.Items.Add(listKeyword);
                    }
                    else
                    {
                        UserSet = true;
                    }
                }
            }
            catch
            {
                MessageBox.Show("Keyword List is not found, and make it.");
                using (System.IO.FileStream hStream = System.IO.File.Create("ListKeyword.txt"))
                {
                    // 作成時に返される FileStream を利用して閉じる
                    if (hStream != null)
                    {
                        hStream.Close();
                    }
                }
            }

            if (UserSet == false)
            {
                if (MessageBox.Show("The producer does not compensate for any damage using this software.", "License confirmation", MessageBoxButtons.OKCancel) != DialogResult.OK)
                {
                    MessageBox.Show("Not agree and can not use this.");
                    Close();
                }
            }
        }

        String Keyword;

        public Form1()
        {
            InitializeComponent();
        }

        private void FileOpen_Click(object sender, EventArgs e)
               {
            if (textBoxURL.Text == "")
            {
                if (keywordCheck() == true)
                {
                    if (writeOutCheck() == true)
                    {

                        FileOpen();
                    }
                 }
   
            }
            else   //URLがあったら
            {



            }
        }
  
        private void buttonGethtml_Click(object sender, EventArgs e)
        {  //作成中
         }

        public Boolean keywordCheck()
        {
            Keyword = comboBoxKeyword.Text;

            if (Keyword == "")
            {
                if (MessageBox.Show("Kyeword is Blank is OK ?", "Notice", MessageBoxButtons.OKCancel) == DialogResult.OK)
                {
                    return true;
                }
                return false;
            }
            else
            {
                return true;
            }

        }

        public bool writeOutCheck()
        {
            if (checkBoxWriteOut.Checked == false && checkBoxPreview.Checked == false)
            {
                MessageBox.Show("Select output");
                return false;
            }
            else
            {
                return true;
            }
        }

        public void FileOpen()
        {

                DateTime dt = DateTime.Now;
                string date = dt.ToString("yyyy_MM_dd_HH_mm_ss");

                OpenFileDialog ofd = new OpenFileDialog();

                if (ofd.ShowDialog() == DialogResult.OK)

                {

                    ViewBoxBackColorSet();
                    textBoxPreview.AppendText(dt.ToString("HH:mm:ss" + Environment.NewLine));

                    //   string[] StrArryData = new string[3]; // 1行分のデータを格納する作業オブジェクト
                    using (var sr = new StreamReader(ofd.FileName))  //型はVariant
                    {
                        int lineCount = 0;
                        if (checkBoxWriteOut.Checked == true)
                        {
                            using (StreamWriter writer = new StreamWriter(date + ".txt", true))
                            {  //インデックス
                                writer.Write("Souce File Name = " + ofd.FileName + Environment.NewLine);
                                writer.Write("Keyword = " + Keyword + Environment.NewLine + "" + Environment.NewLine);
                                writer.Write("======================= " + Environment.NewLine + Environment.NewLine + Environment.NewLine);
                            }
                        }
                        var line = "";
                        while ((line = sr.ReadLine()) != null)      // ストリームの末尾まで繰り返す
                        {
                            int index_check = line.IndexOf(Keyword); //含まれてないときは"-1"
                            if (index_check > -1)
                            {
                                lineCount++;

                                if (checkBoxPreview.Checked == true)
                                {
                                    textBoxPreview.AppendText(line + Environment.NewLine); //追記モード
                                }
                                if (checkBoxWriteOut.Checked == true)
                                {
                                    using (StreamWriter writer = new StreamWriter(date + ".txt", true))
                                    {
                                        writer.Write(line);
                                        writer.Write(Environment.NewLine);
                                    }
                                }
                            }
                        }
                        labelLineCount.Text = lineCount.ToString();
                        ViewBoxBackColorReset();
                    }
                }
          }


        private void buttonClear_Click(object sender, EventArgs e)
        {
            textBoxPreview.ResetText();
            comboBoxKeyword.ResetText();
            textBoxPreview.ResetText();
            labelLineCount.Text = "0";
            textBoxURL.ResetText();
        }

        private void buttonKeywordOpen_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("notepad.exe", @"""ListKeyword.txt""");
        }


        public void ViewBoxBackColorSet()
        {
            textBoxPreview.BackColor = Color.FromArgb(0xdd, 0xdd, 0xdd);
            buttonGethtml.Enabled = false;
            buttonFileOpen.Enabled = false;
            buttonClear.Enabled = false;
            buttonKeywordOpen.Enabled = false;
        }
        public void ViewBoxBackColorReset()
        {
            textBoxPreview.BackColor = Color.White;
            buttonGethtml.Enabled = true;
            buttonFileOpen.Enabled = true;
            buttonClear.Enabled = true;
            buttonKeywordOpen.Enabled = true;
        }

        }

    }

}

C# で配列の要素を並べ替える

要素の中身を最近使ったものから順番に並べ替える。

private void Form1_Load でファイルのなかみを読み込み、ComboBoxにInput。
CombBoxとはTextBoxに複数の要素をDropDownListから選べるもの。
f:id:s51517765:20170429112231j:plain

Listの中身はStreamReaderでよみこむ。
StreamReaderは必ず、srKeyword.Close() で開放しておく。
そうしないと、今度書き込むときにErrorがでる。

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) でアイテムが選択されたときに実行される。
要素の配列をひとつづつずらす。

            for (int n = 7 - 1; n >0 ; n--)
            {
                array_ex[n + 1] = array_ex[n]; //ひとつづつ配列のようそをずらして最新のものを[1]に入れる
              }

最後にファイルに書き込み記録。
ここでは、追記をfalseにして上書きする。
trueでは追記になって、実行されるたびに無駄に要素がふえてしまう。

StreamWriter sw = new StreamWriter("list.txt"<span style="color: #d32f2f">,false</span>, System.Text.Encoding.GetEncoding("shift_jis"))

本当は、重複要素のCheckとかしたい。


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;    //ファイルIO


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

        string[] array_ex = new string[12];
        string[] array_temp = new string[12]; 

        private void Form1_Load(object sender, EventArgs e)
        {     //アプリ起動時に実行される
            int n = 1;
            var listKeyword = "";
            comboBox1.Items.Clear();  //コンボボックスの初期化
            StreamReader srKeyword = new StreamReader("list.txt");
            while ((listKeyword = srKeyword.ReadLine()) != null)
            {                                   
                if (listKeyword == null || listKeyword == "")  //要素の空欄はskip
                { }
                else { 
                    array_ex[n] = listKeyword;
                    comboBox1.Items.Add(listKeyword);
                    n++;
                }
              }
            srKeyword.Close(); //streamを閉じる
        }

        private void button1_Click(object sender, EventArgs e)
        {
               //要素を6つまで表示、必須ではない
                label1.Text = array_ex[1].ToString();
                label2.Text = array_ex[2].ToString();
                label3.Text = array_ex[3].ToString();
                label4.Text = array_ex[4].ToString();
                label5.Text = array_ex[5].ToString();
                label6.Text = array_ex[6].ToString();
            
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {            //コンボボックスからItemが選択されたとき
            //値を取得
           string getItem = comboBox1.SelectedItem.ToString();
            label7.Text = getItem.ToString();
    
            for (int n = 7 - 1; n >0 ; n--)
            {
                array_ex[n + 1] = array_ex[n]; //ひとつづつ配列のようそをずらして最新のものを[1]に入れる
              }

            array_ex[1] = getItem;
            label1.Text = array_ex[1].ToString();
            label2.Text = array_ex[2].ToString();
            label3.Text = array_ex[3].ToString();
            label4.Text = array_ex[4].ToString();
            label5.Text = array_ex[5].ToString();
            label6.Text = array_ex[6].ToString();

            StreamWriter sw = new StreamWriter("list.txt",false, System.Text.Encoding.GetEncoding("shift_jis"));
            foreach (string eee in array_ex )
            {  //ファイルを更新
          
                sw.Write(eee + System.Environment.NewLine);
            }
            
            sw.Close(); //streamを閉じる
        }
     }
}

VC#でソフトウェア使用許諾のようなものを作る

自身が作ったプログラムを公開した時に、使った人が何らかのトラブルが起きてしまったら…。

そのプログラムが動かないだけならたいした問題ではないですが、ローカルのファイルにアクセスしたり、ネット上のデータにアクセスするときは取り返しのつかない状況を起こしてしまうことが起きえます。

たとえば、誤ったプログラムで、ローカルのユーザーのファイルを削除してしまったり…。

そのようなときに、一般にはソフトウェアの製作者は正しい方法であろうとなかろうと提供したソフトウェアの対価を超える補償はしません。

f:id:s51517765:20170415173411j:plain

このような画面は必ずと言っていいほどインストール時に出てくるか、Readmeなどの添付ファイルがあります。

簡易的に、補償しないことを受諾しないと使えない仕組みを作ってみました。
別の、本来の目的のためにプルダウンの中身を”ListKeyword.txt”に書き込む仕組みを作るので、ここに使用許諾の仕組みを追加します。

正しい方法でライセンスキーを入手しない限り、”OKCancel”がでてきて"OK"を押下しないと使えないようにします。

アプリケーションを起動したときに実行されるForm Loadに”ListKeyword.txt”をStreamReaderで読み込みComboBoxのItemに追加する本来の機能に、ライセンスを読み込ませます。

ここではライセンスキーは"123456789012"です。

 if (listKeyword != "123456789012")

”!=” は一致しないときを示す演算子です。
"123456789012"以外はComboBoxのItemに追加する本来の機能を動作させ、"123456789012"のときはelseでライセンスキーをSetします。

  UserSet == true

ここで、UserSetは"Boolean型"の変数です。
Boolean型はtrue or falseの2値をとる変数です。
有効・無効、あり・なし、ON・OFF などを入れるのに使います。
intで0 or 1とする方法を使う人も良く見かけますが、ただしくはBoolean型で定義するべきです。


ライセンスキーがないときは
OKCancelボタンをだします。

  if( MessageBox.Show("このソフトウェアを使用してのいかなる場合も製作者は補償いたしません。", "License confirmation", MessageBoxButtons.OKCancel) != DialogResult.OK)

これは、MessageBoxと選択ボタンを組み合わせたものにさらに、ifで判断を加えたものです。
ここでも"!="を使います。
ここで、”OK”を選択したときにソフトウェアのメイン画面に進み、”キャンセル”を選択したときに許可しない、と考えがちですがこれだとたとえば、右上の×をクリックしてどちらも選択しないと、メイン画面に進めるようになってしまいます。
f:id:s51517765:20170415180229j:plain

これはOK、Cancelと見せかけて実は、その他の選択ができてしまうということです。

あとは、OKが選択されなかったらアプリケーションを終了させるようにします。

close()

あとは、なぜ起動できないのかのメッセージをだしてあげれば親切でしょうか。

    private void Form1_Load(object sender, EventArgs e)
        {
            Boolean UserSet = false;
            var listKeyword = "";
            StreamReader srKeyword = new StreamReader("ListKeyword.txt");
            while ((listKeyword = srKeyword.ReadLine()) != null)      // ストリームの末尾まで繰り返す
            {
                if (listKeyword != "123456789012") //ライセンスキーでないときは本来の動き
                {
                    comboBoxKeyword.Items.Add(listKeyword);
                }
                else
                {
                    UserSet = true; //ライセンスキーがあったら
                }
            }
            
            if (UserSet == false)
            {
               if( MessageBox.Show("このソフトウェアを使用してのいかなる場合も製作者は補償いたしません。", "License confirmation", MessageBoxButtons.OKCancel) != DialogResult.OK)
                {
                    MessageBox.Show("使用許諾に合意しないと使用することはできません。");
                    Close();
                }
            } 
        }

C#でTextファイルへの入出力

例としてHearth Loggerを作ります。
Form1は以下のようなものを作りました。

仕様としては、
・入力は日付、体重、体脂肪率
・プログラムを起動したら、日付は今日の日付を表示。ただし、手入力で変更可能
・OKを押下でファイルに記録。
・OKを押したときグラフCheckboxがONならグラフを表示

f:id:s51517765:20170329203915j:plain


まず、ファイル入出力を扱うので、以下を追加します。

using System.IO;

OKボタンを押下したときに、日付、体重、体脂肪を「カンマ」区切りでtxtもしくはcsvに取り込みます。
日付は後述で自動的に今日の日付を入れるようにしてありますが、体重と体脂肪が空欄の時は追記をスキップします。
チェックボックスがCheckedのときは、グラフを表示します。
グラフの表示にCheckboxの判断を掛け合わせていますが、グラフのインスタンス生成のところはよくわかってないので適切かどうか…。

 private void button1_Click(object sender, EventArgs e)
        {
            double weight;
            double fat;
            if (double.TryParse(textBoxWeight.Text, out weight) == true &&
                double.TryParse(textBoxFat.Text, out fat)==true)
            {
                using (StreamWriter writer = new StreamWriter("data.txt", true)) 
                      //書き込む先のファイル名は"data.text"
                {
                    writer.Write(textboxDate.Text); //textboxの内容を書き込む
                    writer.Write(",");          //任意(ここではカンマ)のTextを書き込む。
                    writer.Write(textBoxWeight.Text);
                    writer.Write(",");
                    writer.WriteLine(textBoxFat.Text);
                    writer.Flush();
                    textBoxWeight.Text = "";  //入力欄であるtextboxをクリア
                    textBoxFat.Text = "";
                }
            }

            Graph Form2 = new Graph();   //グラフのインスタンス生成
            if (checkBoxGraph.Checked == true)  //Checkbox判断
            {
                if (Form2.ShowDialog() == DialogResult.OK) //OKボタンが押されたら
                {

                }
            }

            Form2.Dispose();

        }

日付は今日の日付を取得し、年月日の形式で表示します。

     private void Form1_Load(object sender, EventArgs e)
        {   //Form1が開いたときの動作
            DateTime dt = DateTime.Now; //dtに今日の日付(と現在時刻)
            textboxDate.Text = dt.ToString("yyyy-MM-dd");  //textboxに文字列として"dt"をyyyy-mm-ddの日付形式で
        }

ここまでが、Form1。

ここからForm2。
Form2が読み込まれたときの動作。
始めにまとめて変数を定義しています。
Tryの中でファイルを開いて、日付、体重、体脂肪率にわけて配列に読み込むようにしています。
ここで、Tryは処理に例外が発生した場合、CatchにすすみErrorを出します。
Try,Catchの構文で、予期せぬErrorで止まってしまうのを防ぎます。

   private void Form2_Load(object sender, EventArgs e)
        {
            int n = 1;
            int no = 0;
            int Data_Count=4;
            int Array_Length = 400;
            string[] date = new string[Array_Length];
            string[] Weight_text= new string[Array_Length];
            double[] Weight = new double[Array_Length];
            string[] Fat_text=new string[Array_Length];
            double[] Fat = new double[Array_Length];
            DateTime[] date_style = new DateTime[Array_Length];

try
            { //csvファイルを開いて、日付、体重、体脂肪率にわけて配列に読み込む

                string[] StrArryData = new string[3]; // 1行分のデータを格納する
                using (var sr = new System.IO.StreamReader(@"data.txt")) //読み込むファイル名
                {

                    while (!sr.EndOfStream) //ファイルエンドまで
                    {
                        var line = sr.ReadLine();    // ファイルから一行読み込む
                        StrArryData = line.Split(','); //一行を区切る

                        foreach (string value in StrArryData) //strArrayDatsをStringとして、そのすべてに対して
                        {

           //Data3つごとに分けて配列に格納
                            if (n % 3 == 1)
                            {
                                date[no] = value;
                                DateTime.TryParse(date[no], out date_style[no]); //textをDateTime型に
                            }
                            else if (n % 3 == 2)
                            {
                                Weight_text[no] = value;
                                double.TryParse(Weight_text[no], out Weight[no]); //Textを数値に型変換
                            }
                            else if (n % 3 == 0)
                            {
                                Fat_text[no] = value;
                                double.TryParse(Fat_text[no], out Fat[no]);
                                no++;
                            }
                            n++;
                        }
                        Data_Count = no;
                    }
                }
            }
           catch (System.Exception ee)
            {
                MessageBox.Show("Error");
                // ファイルを開くのに失敗したとき
            }

次に、グラフの表示内容

           // 1.Seriesの追加
            Chart1.Series.Clear();
            Chart1.Series.Add("Weight (kg)");
            Chart1.Series.Add("Body fat (%)");
            

            // 2.グラフのタイプの設定
              Chart1.Series["Weight (kg)"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
              Chart1.Series["Weight (kg)"].MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Diamond;
              Chart1.Series["Body fat (%)"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
              Chart1.Series["Body fat (%)"].MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Diamond;
          
            // 3.座標の入力
            for (no = 0; no < Data_Count; no++)
            {
                Chart1.Series["Weight (kg)"].Points.AddXY(date_style[no],Weight[no]);
                    Chart1.Series["Body fat (%)"].Points.AddXY(date_style[no], Fat[no]);
               }

グラフはこのページを参考にした…というより丸写しに近い。
whoopsidaisies.hatenablog.com

f:id:s51517765:20170329220510j:plain