大復活C#学習_全角を半角に変換する
これまで作ってきた干支を算出するプロジェクトは、.NET Coreのコンソールアプリを用いて書いている。
全角数字を半角と誤って入力するとエラーになるので、例外処理で全角を半角に変換するコードをVisual Basicを参照して処理するように試みたがうまくゆかない。
初心者には行き詰まりはつらい。一日かかって調べて、ようやくその理由が分かった。
C#には半角や全角を交互に変換するメソッドはないので、Visual Basicを参照して、using Maicrosift.VisualBasicと宣言し、全角を半角に変換するのであればStrings.StrConv(source, VbStrConv.Narrow, 0x0411)を用いる。しかし、である。
そもそも、.NET Coreを用いたCUIのソリューションエクスプローラの欄に<参照>の表示がない。調べるとNuGetでインストールすればよいと書いてあったのでやってみるがエラーになる。
そこで、最初からやり直し、CUIを.NET Coreではなく、.NET Frameworkのコンソールアプリで作り直してみると、ソリューションエクスプローラーに<参照>が表示されるし、Visual Basicのメソッドもエラーにならずに作動した。
このことから、素人の浅知恵で誤解かもしれないが、Visual Basicのメソッドを使用したい場合は.NET Coreではなくて.NET Frameworkを使わないといけないと判断した。このあと誤解が解けるようであれば訂正するつもりだが、すでにC#は.NET Coreから.NET 5に移行する方針で、NET FrameworkやVisual Basicも開発は終了しているとのことなので、その状況のなかで起きていることかもしれない。今後はどうなるかわからないので、困惑してしまう。これだけで一日かかってしまった。
でも解決して気分はすっきり。
ちなみに、コードは簡単だ。昨日のコードに追加した例外処理中の肝心な部分だけ備忘録として記載する。
**********
using Microsoft.VisualBasic; //冒頭で宣言して以下のコードを例外処理に追加
//全角→半角変換」
string source = etoYear; //わざと変換して見える化する
string etoYearCorrected = Strings.StrConv(source, VbStrConv.Narrow, 0x0411);
Console.WriteLine(" ⇒ 全角数字を半角に変換しました。");
etoYear = etoYearCorrected; //もとに戻す
大復活C#学習_干支(十干十二支)の算出
西暦の年数から干支(十干十二支)を求めるプロジェクトを作ってみた。
十干は西暦を10で割った余り、十二支は西暦の年に8を足して12で割った余りから算出した(追記20210220:誤りがあったので修正した)。
干支とよく似た年号の数え方に民間信仰の「九星気学」という占術がある。
計算した1950年は「五黄の寅」と呼ばれるが、五黄とは五黄土星の意味で、これは九星気学によって年の周期を9年ごとに、一白水星(いっぱくすいせい)、二黒土星(じこくどせい)、三碧木星(さんぺきもくせい)、四緑木星(しりょくもくせい)、五黄土星(ごおうどせい)、六白金星(ろっぱくきんせい)、七赤金星(しちせききんせい)、八白土星(はっぱくどせい)、九紫火星(きゅうしかせい)に当てはめるもの。
「五黄の寅」(「ごおうのとら」、一般にはこれが訛って「ごうのとら」)は九星と十二支を組み合わせたもので、36年周期で巡ってくる「強運の運勢」をいう。
追記:ここで試してみると数字を全角文字で入力するとエラーになる。C#には全角を半角に変換するライブラリは用意されていないようだ。簡単に変換するにはMicrosoft.VisualBasicを参照してString.StrConvメソッドを使うとよいらしい。
判定だけであれば、以下で処理できた。
if (System.Text.RegularExpressions.Regex.IsMatch(etoYear, "^[0-9]+$") == false)
追記の追記の追記:干支の支の計算に誤りがあったので修正した。正しくは西暦年に8を足して12で割った値を配列[0]から数える。
追記の追記:修正してみた(未修正版は削除した)。2019版Visulal StudioではすでにクラスメソッドでMicrosoft.VisualBasicが参照できるようになっているようだ。試しに最初にusing Microsoft.VisualBasic;を記載してもエラーにはならなかった。最終版をつくるときにはwhile(true),try,catchを入れてエラー処置で全角を半角に変換するつもり(未実施)。
*******************
(修正版)
using System;
//using Microsoft.VisualBasic; //全角を半角の変換するときに使う予定
namespace eraEto_sample1
{
class Program
{
static void Main( )
{
Console.WriteLine("干支の計算");
/*
* 干支(子丑寅の順の場合)
西暦年に8を足し12で割った余りが配列の順番(0から)
子(ね)・丑(うし)・寅(とら)・卯(う)・辰(たつ)
巳(み)・午(うま)・未(ひつじ)・申(さる)・酉(とり)
戌(いぬ)・亥(い)」の12種類
*/
string eraEtoSi = new string[12] {
"子(ね)",
"丑(うし)",
"寅(とら)",
"卯(う)",
"辰(たつ)",
"巳(み)",
"午(うま)",
"未(ひつじ)",
"申(さる)",
"酉(とり)",
"戌(いぬ)",
"亥(い)"
};
/*
*十干(じっかん)の求め方:西暦の末尾の値(10で割った余り)
0 1 2 3 4 5 6 7 8 9
庚 辛 壬 癸 甲 乙 丙 丁 戊 己
*/
string eraEtoJikkan = new string[10]{
"庚(かのえ)",
"辛(かのと)",
"壬(みずのえ)",
"癸(みすのと)",
"甲(きのえ)",
"乙(きのと)",
"丙(ひのえ)",
"丁(ひのと)",
"戊(つちのえ)",
"己(つちのと)"
};
Console.WriteLine("================== 干支 ====================");
Console.WriteLine();
Console.Write(" 西暦の入力(半角数字)⇒ ");
string etoYear = Console.ReadLine();
//修正版で以下を追加。全角数字の入力で終了
if (System.Text.RegularExpressions.Regex.IsMatch(etoYear, "^[0-9]+$") == false)
{
Console.WriteLine(" エラー:半角数字を入力して再試行してください!");
Console.ReadKey();
return;
}
int year = int.Parse(etoYear);
int i = year % 10;
int j =(year +8) % 12 ;
string etoJikkan = eraEtoJikkan[i];
string etoSi = eraEtoSi[j];
Console.WriteLine(" 干支は " + etoJikkan + etoSi);
Console.ReadKey();
}
}
}
修正後のエラー処理画面(全角数字を入力した場合)
大復活C#学習_フォームを用いてサインカーブを描く
フォームを用いてグラフを描いてみる。
もっともポピュラーなサインカーブを描く。
ツールボックスで<データ>からchartを選択してグラフを表示する。
Form1.cs[デザイン]の画面に棒グラフのサンプルが表示されるので、グラフ領域をクリックして、プロパティウインドウの<Series>のコレクションを選択する。
コレクションのリストからグラフの種類や属性を決める。x軸、y軸の最大値、最小値、罫線の間隔を設定する。
Form1.csに切り替えてプロジェクトを書く。
サイン値は角度をラジアンの変換して計算する(C = Math.PI / 180)。
グラフの色や最大値などの細かい設定は随時行う。
あまり使いやすいとは言えないが、とりあえずグラフが描けたのでよしとする。
*********************
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;
namespace graphSample_2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
double x1 = new double[360];
double y1 = new double[360];
double c = Math.PI / 180;
for (int i = 0; i < 360; i++)
{
x1[i] = i ;
y1[i] = Math.Sin((double)i* c );
chart1.Series["S1"].Points.AddXY(x1[i], y1[i]);
chart1.ChartAreas[0].AxisX.Maximum = 360;
chart1.ChartAreas[0].AxisX.Minimum = 0;
}
}
}
}
大復活C#学習_和暦を使う
和暦から西暦を求めるプロジェクトを作成した。
西暦から和暦を求めることも作ってみたが、フォームを作ったときには表示することにする。
今回は基本となる和暦から西暦を求め、満年齢を計算するプログラムを記載する。
使用するクラスにusing System.Globalizationを追加。
System.Globalization.Cultureinfoは各地の文化(カルチャ)固有の情報を扱うためのクラスで、カルチャ名に"ja-JP"を指定してインスタンス化すると「日本語の日本」を指定したことになる。
西暦を和暦に変換するには、DateTimeFormat.CalendarプロパティにJapaneseCalendarクラスのインスタンスを設定する。
今日の日付はDateTime.Todayで求める。
繰り返しは、While(true)を用いて、終了は<Enter>の入力とした。
例外処理は、try{}、catch{}を用いた。goto label を使いたかったが、教科書では使うべきではないと書いてあった。同じメソッドのなかであればlabelがどこにあるかすぐにわかるのでスパゲッティになりにくいと思うが行儀よくtry、catchにしてみた。
追記:干支を計算するほうが面白いので、フォームで作る時は追加することにする。専用のクラスがあるようだ(JapaneseLunisolarCalendarクラス)。
*************************
using System;
using System.Globalization; //使用するクラス
namespace AgeTest1
{
class Program
{
static void Main()
{
//DateTimeを使う
Console.WriteLine();
CultureInfo culture = new CultureInfo("ja-JP", true);
culture.DateTimeFormat.Calendar = new JapaneseCalendar();
Console.WriteLine("==================CUIで基本プログラミング==================");
DateTime today = DateTime.Today; //今日の日付
//------------CUI for Form Program-------------
Console.WriteLine("=================フォーム準備のためのCUI=====================");
Console.WriteLine();
Console.WriteLine(" 元号は漢字で入力、年月は数字で入力");
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("===========================================================");
while (true)
{
try
{
string genGo;
string nenYear;
string getuMonth;
string nichiDay;
Console.Write(" 元号 = ");
genGo = Console.ReadLine();
if (genGo == "") // 繰り返しの終了
{ return; }
Console.Write(" 年 = ");
nenYear = Console.ReadLine();
Console.Write(" 月 = ");
getuMonth = Console.ReadLine();
Console.Write(" 日 = ");
nichiDay = Console.ReadLine();
Console.WriteLine();
string nenGappi = genGo + nenYear + "/" + getuMonth + "/" + nichiDay;
Console.WriteLine(" ⇒ 入力の確認: " + genGo + nenYear + "年" + getuMonth + "月" + nichiDay + "日");
DateTime finalDate = DateTime.Parse(nenGappi, culture.DateTimeFormat);
//Console.WriteLine(" ⇒ 西暦変換後の出力 = " + finalDate);//出力は1950/11/16 0:00:00
Console.WriteLine(finalDate.ToString(" ⇒ 西暦 yyyy年MM月dd日"));//月は大文字
//誕生日の日付から年齢を計算する
int ageOld = today.Year - finalDate.Year;//満年齢の計算
if (finalDate > today.AddYears(-ageOld)) //年齢の修正
ageOld--;
Console.WriteLine();
Console.WriteLine();
Console.WriteLine($" 年齢:満{ageOld}歳");
Console.WriteLine();
Console.WriteLine("=======================終了時は<Enter>=====================");
Console.WriteLine();
}
catch
{
Console.WriteLine();
Console.WriteLine(" ⇒ 入力に誤りがあります");
Console.WriteLine();
}
}
}
}
}
大復活C#学習_GUI(フォーム .NET Framework)を使う
しばらく冬眠状態だった。というわけではなくCUIで基礎学習に精進した。
あらたに基礎学習用に「基礎から学ぶ C#の教科書ー改訂新版ーC#8対応」(WINGSプロジェクト高江賢著、山田祥寛監修、日経BP社、2900円+税)を購入した。この本は表題のごとく基礎から中級までしっかり解説してある。この本にはGUIのうちWPF(Windows Presentation Foundation)を用いたGUIアプリケーションの入門が記載されている。これはXAML(ザムル)を用いてプログラムを書く。いずれはこのWPFが主流になるのだろう。少しC#とは違うところがあるようだ。
一方、「C#「超」入門」(SB Creative)には.NET Frameworkのフォームを用いたGUI入門が載っている。これはC#で書く。混乱しないように、手始めに「フォーム」をGUIに用いて学習してみることにした。
「基礎から」には電卓アプリ作成の例が載っているので、いずれフォームとWPFの両者を学習して比較してみたいと思っている。
手始めは肥満度評価のBMIアプリの作成にチャレンジした。
はじめてのフォームは意外と簡単だった。ついでに体表面積の計算も付けてみた。
FormにLabel、TextBoxを貼り付けて、ButtonにイベントハンドラをC#で記載してできあがり。
丸写しで作成したので、これが完璧かどうかは分からないが、試した限りではバグはでなかった。
通常用いる簡単な科学計算アプリならこれで十分に出来そうだ。夢としては、昔やった離散フーリエ変換をこれでやってみたい。
******
public Form1()
{
InitializeComponent();
}
private void CalcButtonClicked(object sender, EventArgs e)
{
float heightCm;
float weightKg;
bool success1 = float.TryParse(this.heightCmBox.Text, out heightCm);
bool success2 = float.TryParse(this.weightKgBox.Text, out weightKg);
if (success1 && success2)
{
float calcBmi = (float)(weightKg / heightCm / heightCm * 10000);
this.calcBmiBox.Text = calcBmi.ToString("00.00");
float calcBsa = (float)(Math.Pow(weightKg, 0.444) * Math.Pow(heightCm, 0.663) * 0.008883);
this.BsaBox.Text = calcBsa.ToString("0.000");
calcBmi = 0;
}
if(heightCm < 2.5)
{
MessageBox.Show("身長はセンチメートルで入れてください");
}
else if (weightKg > 1000)
{
MessageBox.Show("正しい値を入れてください");
}
}
private void ClickClear(object sender, EventArgs e)
{
this.heightCmBox.Text = " ";
this.weightKgBox.Text = " ";
this.calcBmiBox.Text = " ";
this.BsaBox.Text = " ";
}
大復活C#学習_Dictionaryの準備
Listではできないデータの紐づけをDictinaryを学習して試す。初めはまずもっとも初歩の一覧をコードに書き込み表示する方法を学ぶ。
最初にSystem名前空間で、Linq(今回初めて使う)クラス、Consoleクラス、Collectionクラスの使用を宣言する。これでだいぶ記載が単純化されて見やすくなる(はずだ)。
4名の学生の名前とテストの点数をサンプルとして用いてDictionaryについてもっとも基本となる初歩を学習する。
**************
using System;
using System.Collections.Generic;//CollectionクラスのGeneric メソッドを使う
using System.Linq; //Linqクラスを使う
using System.Console; //Consoleクラスを使う
namespace dictionaryPractice1219
{
class Program //メインのプログラム
{
static void Main(string[] args)
{
GamenHyoji g = new GamenHyoji();
g.gamenHyoji();
DictPractice d = new DictPractice();
d.Practice();
}
}
class GamenHyoji //初期画面の表示
{
public void gamenHyoji()
{
Title = "dictionaryの学習";
WriteLine();
WriteLine(" =============================");
WriteLine();
WriteLine(" Dictionaryの学習(ver 0.0)");
WriteLine();
WriteLine(" =============================");
WriteLine();
}
}
class DictPractice //dictionaryの作成と表示
{
public void Practice()
{
//Dictionary型の変数を作る
Dictionary<string, float> testScore =
new Dictionary<string, float>();
//名前と成績のデータを入れる
testScore.Add("あたろう", 50.0f);
testScore.Add("じろきち", 67.0f);
testScore.Add("さんじ", 48.0f);
testScore.Add("よのすけ", 72.0f);
//dictionary一覧の表示
// 注:個別の点数表示はConsole.WriteLine(testScore["さんじ"])と書く;
//
foreach (KeyValuePair<string, float> kvp in testScore)
{
string name = kvp.Key;
float score = kvp.Value;
WriteLine($" {name} の得点は {score}点 ");//$は文字リテラルの変換
}
ReadLine();
}
}
}
大復活C#学習_Listの改良(平均値の計算ver 2.0)
最初に件数を入力するのであれば配列と同じなのでListを用いるメリットが生かされないから、仮に最大件数を20件として設定しておいて、入力を途中で中断するプログラムに変更した。
実際は値をいちいち入力して計算することはないかもしれないが練習である(でも、教えている今のクラスの学生数は20なのでちょっと計算するにはよいかもしれないナ)。
できれば学生名と点数を紐付けて集計したい。Dictionaryを用いたいがこれがなかなかの難物だ。手元の教科書には詳細な記載がない。
****** 平均値の計算(ver 2.0) ******
class CalcList
{
public CalcList() { }
public void Calclist()
{
//Listの最大件数は20件と設定
string value; //値もstring型、あとでint型に変換
int w;
var sum = 0;
float mean;
int maxW = 0;
int minW = 0;
Console.WriteLine(" 件数は最大20件以内です ");
Console.WriteLine();
int x = 20;//最大入力件数の設定。ここでは20件とする
//Listの作成
List<int> numList = new List<int>(); //numというnumListを作る
for (int n = 0; n < x; n++)
{
Console.Write(" " + (n + 1) + "番目の整数の値は(<Enter>で終了)?__ ");
value = Console.ReadLine();//値の入力
if (value == ""){
Console.WriteLine();
Console.Write(" 入力が終了されました.");
x = n ;
break;
}
w = int.Parse(value);
sum += w; //合計を求める
}
Console.WriteLine(" 件数は {0} 件です", x);
Console.WriteLine();
//以下は初版とおなじ
float y = x;
mean = sum / y;
//昇順にソートする
Console.WriteLine();
Console.WriteLine(" 昇順にソートの結果を表示します");
Console.WriteLine();
numList.Sort();
for (int i = 0; i < numList.Count; i++)
{
Console.WriteLine(" " + numList[i]);
maxW = numList[i];
minW = numList[0];
}
//標準偏差を計算する
double bunsan_calc1 = 0;
double sd;
for (int a = 0; a < numList.Count; a++)
{
bunsan_calc1 += Math.Pow((numList[a] - mean), 2.0);
}
double b = numList.Count;
sd = Math.Sqrt(bunsan_calc1 / b);
Console.WriteLine();
Console.Write(" 合計 = {0}", sum);
Console.Write(" 平均 = {0:##.##}", mean);
Console.WriteLine(" 標準偏差 = {0:##.#}", sd);
Console.WriteLine(" 最小値 {0} , 最大値 {1} ", minW, maxW);
Console.ReadLine();
}
}