[C++] 文字列操作

C# の文字列操作の気分で C++ にやってくると、C++ の文字列操作は メモリ操作（例えば主記憶装置上の操作）なことに気づく。

このサンプルコードに 表現の著作性はないが 気になるなら MIT License で。https://opensource.org/licenses/MIT

# 前準備

## **const char*** a と **size_t** b がやってきた

```cpp
#include <string> // std::string
// ↑ファイルの冒頭あたりに置く

std::string myString(a, b);
```

(Visual Studio 2015)
これで a, b で渡された変数は、std::string 型の文字列 myString 変数として使える。

## 文字列の配列(1)

```cpp
#include <string> // std::string
#include <iostream> // std::cout
// ↑ファイルの冒頭あたりに置く

static std::string a[] = {"か","きく","けこ"};

// でいける。

std::string c = a[0] + a[1] + a[2];
std::cout << c << std::endl;

// 出力:
// かきくけこ
```

(Visual Studio 2015)

### 文字列の配列(2)

```cpp
#include <string> // std::string
#include <iostream> // std::cout
// ↑ファイルの冒頭あたりに置く

std::string a[10] = {};

if ("" == a[0]) { std::cout << "空0" << std::endl; }
if ("" == a[1]) { std::cout << "空1" << std::endl; }
if ("" == a[2]) { std::cout << "空2" << std::endl; }
if ("" == a[3]) { std::cout << "空3" << std::endl; }
if ("" == a[4]) { std::cout << "空4" << std::endl; }
if ("" == a[5]) { std::cout << "空5" << std::endl; }
if ("" == a[6]) { std::cout << "空6" << std::endl; }
if ("" == a[7]) { std::cout << "空7" << std::endl; }
if ("" == a[8]) { std::cout << "空8" << std::endl; }
if ("" == a[9]) { std::cout << "空9" << std::endl; }

// 結果:
// 空0
// 空1
// 空2
// 空3
// 空4
// 空5
// 空6
// 空7
// 空8
// 空9
```

(Visual Studio 2015)
配列の要素数を指定しておけば、空文字列で埋めてくれる実装のようだ。

# 文字列連結(1)

```cpp
#include <string> // std::string
#include <iostream> // std::cout
// ↑ファイルの冒頭あたりに置く

std::string a = "あいう";
std::string b = "えお";

// なら単に

std::string c = a + b;

// と書けばいける。

std::cout << c << std::endl;

// 出力:
// あいうえお
```

(Visual Studio 2015)

## 文字列連結(2)

```cpp
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
// ↑ファイルの冒頭あたりに置く

static std::string a = "変";

static std::ostringstream s;
s << "あ" << 1 << " " << (3+7) << " " << false << a << std::endl;

// と書けば。

std::cout << s.str() << std::endl;

// 出力:
// あ1 10 0変

// false が 0 になっているのは面食らう。
```

(Visual Studio 2015)

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

```cpp
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
// ↑ファイルの冒頭あたりに置く

std::string a, b, c;
std::istringstream("さし す せそ") >> a >> b >> c;

// と書けば

std::cout << "a=[" << a << "]" << std::endl;
std::cout << "b=[" << b << "]" << std::endl;
std::cout << "c=[" << c << "]" << std::endl;

// 出力:
// a=[さし]
// b=[す]
// c=[せそ]
```

(Visual Studio 2015)
この書き方だと、全角スペースでは区切ってくれない。
もう少し調べる。

```cpp
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
// ↑ファイルの冒頭あたりに置く

std::string a, b;
std::istringstream s("たち つ てと");
s >> a >> b;

// と書けば

std::cout << "a=[" << a << "]" << std::endl;
std::cout << "b=[" << b << "]" << std::endl;
std::cout << "s=[" << s.str() << "]" << std::endl;

// 出力:
// a=[たち]
// b=[つ]
// s=[たち つ てと]
```

(Visual Studio 2015)
ストリームで流しても、元の文字列は残っているようだ。
さらに　調べる。

```cpp
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
// ↑ファイルの冒頭あたりに置く

std::string a, b, c, d, e, f, g;
std::istringstream s("な にぬ ねの はひ ふ へほ");
s >> a;
s >> b;
s >> c;
s >> d;
s >> e;
s >> f;
s >> g;

// こう書いて

std::cout << "a=[" << a << "]" << std::endl;
std::cout << "b=[" << b << "]" << std::endl;
std::cout << "c=[" << c << "]" << std::endl;
std::cout << "d=[" << d << "]" << std::endl;
std::cout << "e=[" << e << "]" << std::endl;
std::cout << "f=[" << f << "]" << std::endl;
std::cout << "g=[" << g << "]" << std::endl;
std::cout << "s=[" << s.str() << "]" << std::endl;

// 結果:
// a=[な]
// b=[にぬ]
// c=[ねの]
// d=[はひ]
// e=[ふ]
// f=[へほ]
// g=[]
// s=[な にぬ ねの はひ ふ へほ]
```

(Visual Studio 2015)
どこまでコピーを終えたか、は記憶されているようだ。

# 比較 等しい

```cpp
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
// ↑ファイルの冒頭あたりに置く

std::string a = "あいう";

if      ("あ"         == a) { std::cout << "答1" << std::endl; }
else if ("あい"       == a) { std::cout << "答2" << std::endl; }
else if ("あいう"     == a) { std::cout << "答3" << std::endl; }
else if ("あいうえ"   == a) { std::cout << "答4" << std::endl; }
else if ("あいうえお" == a) { std::cout << "答5" << std::endl; }
else                       { std::cout << "答6" << std::endl; }

std::string unuse;
std::getline(std::cin, unuse);

// 結果:
// 答3
```

(Visual Studio 2015)
等号で比較できたが　本当にこれでいいのか知らない。

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

```cpp
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::istringstream, std::ostringstream

#include <vector> // 可変長配列

// 参照 : C++での文字列の使い方まとめ(string) (Futurismo) http://futurismo.biz/archives/1856
int main()
{
	// 与件
	std::istringstream data("--加納 こはだ かんぱち まぐろ --木曽 あなご かっぱ --久慈 たまご あかがい とろ いか");
	// データ構造: --人物 寿司ネタ（複数件）※繰り返し
	// 人物、寿司ネタは可変個数設定可能

	// 受け皿
	std::vector<std::string> persons; // 結果はこれらの配列に入れる
	std::vector<std::vector<std::string>> dishes;

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

	// 解析器
	std::string a;
	while (data >> a) {
		if ("--"==a.substr(0,2))//先頭の2文字が「--」の場合
		{
			persons.push_back(a.substr(2)); // 最初の２文字「--」の次から
			dishes.push_back(std::vector<std::string>()); // リストの中にリストを準備
		}
		else { dishes[dishes.size() - 1].push_back(a); } // 要素数-1 で最後の要素

		std::cout << "a=[" << a << "]" << std::endl;
	}

	// 結果
	int i = 0;
	for(std::string person : persons)
	{
		for (std::string dish : dishes[i])
		{
			std::cout << "(" << i << ") person=[" << person << "] dish=[" << dish << "]" << std::endl;
		}
		i++;
	}

	std::cout << "Please, push any key." << std::endl;
	std::string unuse;
	std::getline(std::cin, unuse);
	return 0;
}
```

(Visual Studio 2015)
g++ だと 「while (data >> a) {」の判定で止まってくれないようだ？