2.12.5. 文字列#

2.12.5.1. char 型#

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

#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 を置く必要があります。ダブルクォーテーションで文字列を指定した場合は、ヌル文字が自動的に追加されます。

#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;
}

2.12.5.2. char 型ポインター#

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

#include <stdio.h>

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

2.12.5.3. string 型#

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

#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 に渡すことで変換できます。配列の場合はヌル文字までが自動的に文字列として扱われます。

#include <iostream>
#include <string>

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

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

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

#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 では、文字列を配列と同じように扱うことができます。例えば、インデックスを指定して特定の文字にアクセスできます。

#include <iostream>
#include <string>

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

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

#include <iostream>
#include <string>

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

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

#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 が返されます。

#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 を使うと、指定した位置と長さの文字列を別の文字列に置き換えられます。

#include <iostream>
#include <string>

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

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

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

#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;
}