C++ の文字列操作まとめ

AtCoderに取り組んでいて迷うことが多々あったので、
C++における文字列の操作についてまとめます。（適宜追記予定です）


##基本
文字列変数の宣言・値の代入を行い、標準出力します。

```c++:sample.cpp
#include<iostream>
#include<string>
using namespace std;

int main() {
  string s1 = "testtest";
  string s2 = "";
  string s3 = "TEST";
  
  cout << "s1=" << s1 << ", s2=" << s2 << ", s3=" << s3 << endl; 
}
```

```c++:result
s1=testtest, s2=, s3=TEST
```


##n番目文字の抽出
[ ]で取得したい文字列のインデックスを指定します。

```c++:extract
  s1 = "testtest";
  char c = s1[3];
  cout << "c = " << c << endl;
```

```c++:result
c = t
```

##文字列の長さを取得
size()を使用します。

```c++:length
  s1 = "testtest";
  s2 = "";
  cout << "s1.size()= " << s1.size() << endl;
  cout << "s2.size()= " << s2.size() << endl;
```

```c++:result
s1.size()= 8
s2.size()= 0
```

##文字列が空かどうか判定
empty()を使用します。

```c++:checkIfEmpty
  S1 = "testtest";
  s2 = "";
  cout << "s1.empty = " << s1.empty() << endl;
  cout << "s2.empty = " << s2.empty() << endl;
```

```c++:result
s1.empty = 0
s2.empty = 1
```
s2は空の文字列なので1 (=true)が返ってきます。


##文字列の連結
シンプルに + で足し算できます

```c++:sum
  string s1 = "testtest";
  string s3 = "TEST";

  string s1pls3 = s1 + s3;
  cout << "s1 + s3 = " << s1pls3 << endl;
```

```c++:result
s1 + s3 = testtestTEST
```


##文字列の分割
n番目以降の文字列を取り出す場合はsubstr(n)とします。

```c++:sub1
  s1 = "testtest";
  cout << "s1.substr(3) = " << s1.substr(3) << endl;
```

```c++:result
s1.substr(3) = ttest
```

n番目以降の文字列をm文字だけ取り出す場合はsubstr(n, m)とします。

```c++:sub2
  s1 = "testtest";
  cout << "s1.substr(3,3) = " << s1.substr(3,3) << endl;
```
```c++:result
s1.substr(3,3) = tte
```

##文字列を任意の文字で分割
任意の文字での文字列分割(split)はc++に定義されていません。
自分で実装しましょう！
[参考: C++におけるstringのsplit](https://qiita.com/iseki-masaya/items/70b4ee6e0877d12dafa8)


##文字列の削除
n文字目以降の文字列を削除したい場合はerase(n)とします。

```c++:erase1
  s1 = "testtest";
  cout << "s1.erase(3) = " << s1.erase(3) << endl;
```
```c++:result
s1.erase(3) = tes
```


n文字目以降の文字列をm文字だけ削除したい場合はerase(n, m)とします。

```c++:erase2
  s1 = "testtest";
  cout << "s1.erase(3,2) = " << s1.erase(3, 2) << endl;
```

```c++:result
s1.erase(3,2) = tesest
```

##文字列の挿入
n文字目から文字列Xを挿入したい場合はinsert(n,X)とします。

```c++:insert
  s1 = "testtest";
  cout << "s1.insert(3,IN) = " << s1.insert(3, "IN") << endl;
```
```c++:result
s1.insert(3,IN) = tesINttest
```

##文字列の検索
探索したい文字列Xを用いてfind(X)とすると、該当する位置を返します。

```c++:find1
  s1 = "testtest";
  cout << "s1.find(s) = " << s1.find("s") << endl;
```
```c++:result
s1.find(s) = 2
```
sの最初の出現位置が返ります。

もしも検索文字列が見つからない場合には以下のようになります。

```c++:find1
  s1 = "testtest";
  cout << "s1.find(w) = " << s1.find("w") << endl;
```
```c++:result
s1.find(w) = 18446744073709551615
```
検索文字列が見つからないときは string::npos という値が返るようです。
それが何故こんな大きな数字になるのかは、以下の記事で解説されています。
[std::string::nposの正体](https://qiita.com/yakigac/items/8797cc256d6dcbd5e36a)

では string::nposを使って、検索失敗の場合の場合分けをしてみます。

```c++:find3
  s1 = "testtest";
  cout << "s1.find(W) == string::npos --> " << (s1.find("W") == string::npos) << endl;
```
```c++:result
s1.find(W) == string::npos --> 1
```
"testtest" の中に "W"は含まれないので、string::nposとなっています（1 (=true)が返ります）。


##文字列の置換
n番目から数えてm個の文字列をXに置換したい場合はreplace(n,m,X)とします。

 ```c++:find3
  s1 = "testtest";
  cout << "s1.replace(2, 1, W) = " << s1.replace(2, 1, "W") << endl;
```
```c++:result
s1.replace(2, 1, W) = teWttest
```

##文字列の比較（一致判別）
文字列と文字を用いた比較の例です。

 ```c++:comp
//文字列
if(s1 == "test" ){
  cout << "test" << endl;
}
//文字
if(s1[0] == 't' ){
  cout << "t" << endl;
}
```
##文字列の比較2(小文字大文字英数字判別)

英字大文字小文字数字の判定。（ひらがなカタカナ漢字の判別は、またどこかで必要になったら調べて追記します）

 ```c++:comp
//文字が英小文字かどうか判定
if(s1[0] >= 'a' && s1[0] <= 'z'){
  cout << "small" << endl;

//文字が英大文字かどうか判定
}else if(s1[0] >= 'A' && s1[0] <= 'Z'){
  cout << "large" << endl;

//文字が数字かどうか判定
}else if(s1[0] >= '0'){
  cout << "number" << endl;
}
```
もしくは　#include<ctype.h>として、isalpha(判別したい文字)や isdigit(判別したい文字)を利用できます。

```c++:example
#include<iostream>
#include <ctype.h>
using namespace std;

int main() {
  char s;

  cout << "input: " ;
  cin >> s;

  cout << "isalpha: "<<  isalpha(s) << endl;//アルファベットかどうか
  cout << "isdigit: "<<  isdigit(s) << endl;//数字かどうか
  cout << "islower: "<<  islower(s) << endl;//小文字かどうか
  cout << "isupper: "<<  isupper(s) << endl;//大文字かどうか
}  
```

```c++:result
//アルファベット＆小文字入力
input: a
isalpha: 1024
isdigit: 0
islower: 512
isupper: 0

//数字入力
input: 1
isalpha: 0
isdigit: 1
islower: 0
isupper: 0

//アルファベット＆大文字入力
input: A
isalpha: 1024
isdigit: 0
islower: 0
isupper: 256

```
##文字列から数字型へ変換

sstream を使用して、string型に入った数字文字列をint型に変換します。

 ```c++:str2int
#include<iostream>
#include<string>
#include <sstream>
using namespace std;

int main() {
  string s1;
  istringstream ss1;
  int p1;

  cin >> s1;
  ss1 = istringstream(s1);
  ss1 >> p1;

//数字が入ったp1を操作

}
```
##文字型から数字型へ変換
一文字ずつなら難しいことしなくても数字型にできます。

```c++:char2int
  string s = "1";
  int a = s[0]-'0';
  a += 5;

  cout <<  a << endl;
```

```c++:resilt
6
```

##文字列の並び替え
sortを使用して降順昇順並び替えを行います。
（英数字以外には使えないかな...）

 ```c++:sort
  s1 = "482tTest";

  sort(s1.begin(), s1.end());
  cout << s1 << endl;

  sort(s1.begin(), s1.end(), greater<char>());
  cout << s1 << endl;
```
```c++:result
248Testt  //数字1-9▶英大文字A-Z▶英小文字a-z
ttseT842  //英小文字z-a▶英大文字Z-A▶数字9-1
```

##英文字をアルファベット順でN個後にずらして出力　
[参考: abc146 B](https://atcoder.jp/contests/abc146/tasks/abc146_b)
こんな感じ？

```c++:
string s1 = "test";
int N = 5;
printf("%c", (s1[0]+N)); 
```
##末尾の文字削除/末尾に文字追加
[参考: abc043 B](https://atcoder.jp/contests/abc043/tasks/abc043_b)
pop, pushが使える

```c++:
string s1 = "test";

//末尾に'2'を追加
s1.push_back('2');

//末尾の文字削除
s1.pop_back();
```

##回文判定
reverseで反転を行い、元文字列と比較することで実現できます。
（後日 追記）

<br>

以上です。
また何かあれば追記していきます。