# 文字列

## char 型

C/C++ 言語では、1 文字を扱うために `char` 型を使用します。`char` 型のサイズは 1 バイトと決められており、1 つの変数には 1 文字しか格納できません。次の例では、3 つの `char` 変数にそれぞれ文字を代入し、まとめて出力しています。

```c
#include <stdio.h>

int main(void) {
    char a = 'D';
    char b = 'N';
    char c = 'A';

    printf("%c%c%c\n", a, b, c);  // DNA
    
    return 0;
}
```

複数の文字からなる文字列を扱う場合は、`char` 型の配列を利用します。このとき、文字列の最後には必ずヌル文字 `\0` を置く必要があります。ダブルクォーテーションで文字列を指定した場合は、ヌル文字が自動的に追加されます。

```c
#include <stdio.h>

int main(void) {
    char str1[] = {'R', 'N', 'A', '\0'};
    printf("%s (%lu)\n", str1, sizeof(str1)); // RNA (4)

    char str2[] = "DNA";
    printf("%s (%lu)\n", str2, sizeof(str2)); // DNA (4)

    return 0;
}
```

## char 型ポインター

文字列は、`char` 型の配列だけでなく、`char` 型ポインターでも扱うことができます。文字列リテラルを指すポインターを使う場合、内容を書き換えないため `const char*` とするのが一般的です。

```c
#include <stdio.h>

int main(void) {
    const char* str = "DNA";
    printf("%s\n", str);  // DNA
    return 0;
}
```

## string 型

C++ では `std::string` 型を使うことで、文字列をより安全かつ簡単に扱えます。文字列の結合や長さの取得などが直感的に行える点が特徴です。

```cpp
#include <iostream>
#include <string>

int main() {
    std::string str1 = "DNA";
    std::string str2 = "RNA";

    std::cout << str1 + str2 << std::endl;  // DNARNA
    return 0;
}
```

`char` 型配列は、そのまま `std::string` に渡すことで変換できます。配列の場合はヌル文字までが自動的に文字列として扱われます。

```cpp
#include <iostream>
#include <string>

int main() {
    char arr[] = "CGTCAAACGG";
    std::string dna_seq(arr);

    std::cout << dna_seq << std::endl;  // CGTCAAACGG
    return 0;
}
```

`char` 型ポインターから変換する場合も同様に変換できます。

```cpp
#include <iostream>
#include <string>

int main() {
    const char* ptr = "CGTCAAACGG";
    std::string dna_seq(ptr);

    std::cout << dna_seq << std::endl;
    return 0;
}
```

`std::string` では、文字列を配列と同じように扱うことができます。例えば、インデックスを指定して特定の文字にアクセスできます。

```cpp
#include <iostream>
#include <string>

int main() {
    std::string seq = "CGTCAAACGG";
    std::cout << seq[0] << " " << seq[1] << std::endl;  // C G
    return 0;
}
```

文字列の長さは `size()` で取得できます。

```cpp
#include <iostream>
#include <string>

int main() {
    std::string seq = "CGTCAAACGG";
    std::cout << seq.size() << std::endl;  // 10
    return 0;
}
```

複数の文字列を連結する場合は、`+` 演算子を使います。

```cpp
#include <iostream>
#include <string>

int main() {
    std::string mRNA = "CGTCAAACGC" + std::string("CGCCCGATAG") + "AACCAATTGT";
    std::cout << mRNA << std::endl;
    return 0;
}
```

文字列中から特定の部分文字列を探すには、`find` または `rfind` を使用します。`find` は前から、`rfind` は後ろから検索します。見つからない場合は `std::string::npos` が返されます。

```cpp
#include <iostream>
#include <string>

int main() {
    std::string seq = "CGTATACAAACCGGAGCGAAAAC";

    auto pos1 = seq.find("AAA");
    auto pos2 = seq.rfind("AAA");

    std::cout << pos1 << std::endl;  // 7
    std::cout << pos2 << std::endl;  // 19
    return 0;
}
```

`replace` を使うと、指定した位置と長さの文字列を別の文字列に置き換えられます。

```cpp
#include <iostream>
#include <string>

int main() {
    std::string seq = "CGTCAACGTAACCTGC";
    seq.replace(0, 3, "AAAAAAAAAA");

    std::cout << seq << std::endl;
    return 0;
}
```

特定の文字をすべて別の文字に置き換えたい場合は、`find` と `replace` を組み合わせて処理します。次の例では、すべての `T` を `U` に置き換えています。

```cpp
#include <iostream>
#include <string>

int main() {
    std::string seq = "CGTCAACGTAACCTGC";

    for (auto pos = seq.find('T'); pos != std::string::npos; pos = seq.find('T', pos + 1)) {
        seq.replace(pos, 1, "U");
    }

    std::cout << seq << std::endl;  // CGUCAACGUAACCUGC
    return 0;
}
```
