[C#] 文字列操作

関連記事 : http://qiita.com/muzudho1/items/75eac9fea27d64ce856e

# コマンドライン引数 args

```csharp
using System;

class Study_cs
{
    static void Main(string[] args)
    {
        Console.WriteLine("args.Length=[" + args.Length + "]");
        int i = 0;
        foreach (string arg in args)
        {
            Console.WriteLine("(" + i + ")arg=[" + arg + "]");
            i++;
        }

        Console.WriteLine("Please, push any key.");
        Console.ReadKey();
    }
}
```

(Visual Studio 2015)
このまま実行すると、

```
// 結果:
// args.Length=[0]
```

(Ubuntu16.04)

```
mcs study_cs.cs
./study_cs.exe
args.Length=[0]
Please, push any key.
```

引数を与えて実行すると

```
./study_cs.exe -a --bcde > ./study_cs.out.log 2> ./study_cs.err.log

```

標準出力に結果は返ってこないので、ファイルを見に行く。

```
nano study_cs.out.log
```

study_cs.out.log

```
args.Length=[2]
(0)arg=[-a]
(1)arg=[--bcde]
Please, push any key.
```

空白区切りでトークンを取ってくれるようだ。
もう少し調べてみた。

```
./study_cs.exe -a b c d --efg  -h  i > ./study_cs.out.log 2> ./study_cs.err.log
```

半角スペース２個で区切る例も試してみた。

```
args.Length=[7]
(0)arg=[-a]
(1)arg=[b]
(2)arg=[c]
(3)arg=[d]
(4)arg=[--efg]
(5)arg=[-h]
(6)arg=[i]
Please, push any key.
```

# 文字列分割 半角スペース区切り

単純に半角スペースで区切ると

```csharp
using System;

class Study_cs
{
    static void Main(string[] args)
    {
        string[] a = "あい う えお  か   き    く     けこ".Split(' ');

        Console.WriteLine("a.Length=[" + a.Length + "]");
        int i = 0;
        foreach (string b in a)
        {
            Console.WriteLine("(" + i + ")b=[" + b + "]");
            i++;
        }

        Console.WriteLine("Please, push any key.");
        Console.ReadKey();
    }
}
```

こうなってしまう。

```
a.Length=[17]
(0)b=[あい]
(1)b=[う]
(2)b=[えお]
(3)b=[]
(4)b=[か]
(5)b=[]
(6)b=[]
(7)b=[き]
(8)b=[]
(9)b=[]
(10)b=[]
(11)b=[く]
(12)b=[]
(13)b=[]
(14)b=[]
(15)b=[]
(16)b=[けこ]
Please, push any key.
```

(Visual Studio 2015)

連続する半角スペースも1個と考えたいことがあるだろう。その場合、正規表現を使う。

```csharp
using System;
using System.Text.RegularExpressions;

class Study_cs
{
    static void Main(string[] args)
    {
        string[] a = Regex.Replace("あい う えお  か   き    く     けこ"," +"," ").Split();

        Console.WriteLine("a.Length=[" + a.Length + "]");
        int i = 0;
        foreach (string b in a)
        {
            Console.WriteLine("(" + i + ")b=[" + b + "]");
            i++;
        }

        Console.WriteLine("Please, push any key.");
        Console.ReadKey();
    }
}
```

結果

```
// 結果:
a.Length=[7]
(0)b=[あい]
(1)b=[う]
(2)b=[えお]
(3)b=[か]
(4)b=[き]
(5)b=[く]
(6)b=[けこ]
Please, push any key.
```

(Visual Studio 2015)

# 楽しいサンプル・プログラム

解析器

```csharp
using System;
using System.Text.RegularExpressions;
// ↑ファイルの冒頭に書く
```

```csharp
// 与件
string[] data = Regex.Replace("成績 安蘇 95 伊能 88 宇野 75 江田 77 隠岐 100", " +"," ").Split();

// 受け皿
const int NUM = 10;
string[] names = new string[NUM]; // 結果はこれらの配列に入れる。領域は多めに取っておく
string[] scores = new string[NUM];

// 解析器
int m0 = 0; // 記憶0 : データの種類 : 0ニュートラル 1成績
int m1 = 0; // 記憶1 : データの列   : (条件)m0==1成績 : 0氏名 1点数
foreach (string a in data)
{
    switch (m0)
    {
        case 0: // ニュートラル
            switch (a)
            {
                case "成績": m0 = 1; break;
            }
            break;
        case 1: // 成績
            switch (m1%2)
            {
                case 0: names[m1 / 2] = a; m1++; break;
                case 1: scores[m1 / 2] = a; m1++; break;
            }
            break;
    }
}

// 出力
Console.WriteLine("成績発表");
for (int i = 0; i < NUM; i++)
{
    Console.WriteLine(names[i] + "=" + scores[i]);
}

Console.WriteLine("Please, push any key.");
Console.ReadKey();
```

```
// 結果:
成績発表
安蘇=95
伊能=88
宇野=75
江田=77
隠岐=100
=
=
=
=
=
Please, push any key.
```

(Visual Studio 2015)

## 解説
人の感覚で

- ペア　になっている
- ひとかたまり　になっている

というものは、周期として捉える。例) アニメの1クール

例えば 13話 1クール なら

```
num%13
```

と書けば、0～12、0～12 と繰り返す。
結果を 1～13 にしたい場合は +1 するといい。（オフセット）

```
num%13+1
```

読取位置を調整するときも足し算すればいい。（オフセット）

```
(num+10)%13
```

何クール目かを調べたいときは割り算が使える。

```
num/13
```

これも 0 スタートになるので、1スタートにしたい場合は +1 する。

次のようにも書くことができる。スタティックな書き方。

```csharp
using System;
using System.Text.RegularExpressions;
// ↑ファイルの冒頭に書く
```

```
// 与件
string[] data = Regex.Replace("成績 安蘇 95 伊能 88 宇野 75 江田 77 隠岐 100", " +"," ").Split();
// 先頭はデータのタイトル。
// 以降、0氏名、1点数 の繰り返し

// 受け皿
const int NUM = 10;
string[] names = new string[NUM]; // 結果はこれらの配列に入れる。領域は多めに取っておく
string[] scores = new string[NUM];

// 解析器
int m = 0; // 記憶 : カーソル相当
foreach (string a in data)
{
    if (m==0) // ニュートラル
    {
        switch (a)
        {
            case "成績": m++; break;
        }
    }
    else // 成績
    {
        switch ((m - 1) % 2) // タイトル1列分引いて m-1 としている
        {
            case 0: names[(m - 1) / 2] = a; m++; break;
            case 1: scores[(m - 1) / 2] = a; m++; break;
        }
    }
}

// 結果
Console.WriteLine("成績発表");
for (int i = 0; i < NUM; i++)
{
    Console.WriteLine(names[i] + "=" + scores[i]);
}
```

**利点** カーソルが１個　動いているだけ、という理解しやすさ
**欠点** データを１列増やしたいときに　アルゴリズムの変更箇所が比較的多くなる

データが可変長だった場合はどうだろうか？

```csharp
using System; // Console
using System.Collections.Generic; // List<...>
using System.Text.RegularExpressions; // Regex
// ↑ファイルの冒頭に書く
```

```csharp
// 与件
string[] data = Regex.Replace("--加納 こはだ かんぱち まぐろ --木曽 あなご かっぱ --久慈 たまご あかがい とろ いか", " +", " ").Split();
// 人物、寿司ネタは可変個数設定可能

// 受け皿
List<string> persons = new List<string>(); // 結果はこれらの配列に入れる
List <List<string>> dishes = new List<List<string>>();

// 記憶
// 別段用意無し

// 解析器
foreach (string a in data)
{
    if (a.StartsWith("--"))
    {
        persons.Add(a.Substring(2)); // 最初の２文字 -- の次から
        dishes.Add(new List<string>()); // リストの中にリストを準備
    }
    else { dishes[dishes.Count-1].Add(a); } // 要素数-1 で最後の要素
}

// 結果
int i = 0;
foreach (string person in persons)
{
    foreach(string dish in dishes[i])
    {
        Console.WriteLine("(" + i + ") person=[" + person + "] dish=[" + dish + "]");
    }
    i++;
}

Console.WriteLine("Please, push any key.");
Console.ReadKey();
return;
```

```
// 結果:
(0) person=[加納] dish=[こはだ]
(0) person=[加納] dish=[かんぱち]
(0) person=[加納] dish=[まぐろ]
(1) person=[木曽] dish=[あなご]
(1) person=[木曽] dish=[かっぱ]
(2) person=[久慈] dish=[たまご]
(2) person=[久慈] dish=[あかがい]
(2) person=[久慈] dish=[とろ]
(2) person=[久慈] dish=[いか]
Please, push any key.
```