コンテンツにスキップ

C++/標準ライブラリ/string

出典: フリー教科書『ウィキブックス(Wikibooks)』

概要

[編集]

<string> ヘッダーの役割

[編集]

C++標準ライブラリには、多くの便利なヘッダーが含まれており、それぞれが特定の機能を提供しています。その中で、<string> ヘッダーは、文字列を操作するための機能を提供します。このヘッダーは、C++プログラムにおいて文字列操作を簡素化し、かつ強力にするための様々なツールを含んでいます。

従来のC言語では、文字列はヌル終端文字列('\0' で終端された char の配列)として扱われてきましたが、これは直接的なメモリ管理やポインタ操作が必要なため、扱いが難しいものでした。C++では、std::string クラスを提供することで、これらの煩雑な操作を抽象化し、安全かつ直感的に文字列を扱うことができます。

<string> ヘッダーが提供する主な機能には以下が含まれます:

  • 文字列の作成、コピー、結合、部分文字列の取得など、基本的な文字列操作
  • 文字列の検索、比較、置換
  • 数値との相互変換
  • 効率的なメモリ管理
  • 例外安全性と強力な型チェック

これらの機能により、<string> ヘッダーはC++プログラムにおける文字列操作の標準的な方法となっています。

std::string クラスの基本概要

[編集]

std::string クラスは、C++標準ライブラリの一部であり、<string> ヘッダーで定義されています。このクラスは、動的にサイズを変更できる文字列を提供し、多くの便利なメソッドを通じて文字列操作を簡単に行えるように設計されています。

以下に、std::string クラスの基本的な特徴と機能を紹介します。

コンストラクタ

[編集]

std::string クラスは、様々なコンストラクタを提供しています。これにより、文字列を多様な方法で初期化できます。

デフォルトコンストラクタ
空の文字列を作成します。
  std::string s1;
文字列リテラルからのコンストラクタ
文字列リテラルを元に文字列を作成します。
  std::string s2 = "Hello, World!";
コピーコンストラクタ
他のstd::stringオブジェクトからコピーして文字列を作成します。
  std::string s3 = s2;
ムーブコンストラクタ
他のstd::stringオブジェクトからムーブして文字列を作成します。
  std::string s4 = std::move(s3);

文字列の操作

[編集]

std::string クラスは、文字列操作のための多くのメソッドを提供しています。例えば:

append
文字列の末尾に文字列を追加します。
  s1.append("Appended text");
substr
部分文字列を取得します。
  std::string sub = s2.substr(0, 5);  // "Hello"
erase
指定した範囲の文字を削除します。
  s2.erase(0, 6);  // "World!"

文字列の比較

[編集]

std::string クラスは、文字列の比較のための演算子とメソッドを提供しています。

比較演算子
==, !=, <, >, <=, >= を使用して文字列を比較できます。
  if (s2 == "World!") {
      // 条件が真
  }
compare
詳細な比較を行うためのメソッドです。
  int result = s2.compare("World!");

文字列の検索

[編集]

std::string クラスは、文字列内で部分文字列を検索するためのメソッドも提供しています。

find
指定した文字列または文字が最初に現れる位置を返します。
  size_t pos = s2.find("World");

入出力

[編集]

std::string クラスは、標準入出力ストリームとの連携も簡単に行えます。

入力
std::cin を使用して文字列を読み取ることができます。
  std::string input;
  std::cin >> input;
出力
std::cout を使用して文字列を出力できます。
  std::cout << s2;

これらの機能により、std::string クラスはC++プログラミングにおいて非常に強力で便利なツールとなっています。次の章では、これらの機能を詳しく見ていきましょう。

基本操作

[編集]

文字列リテラルと std::string オブジェクト

[編集]

C++では、文字列を扱う方法として主に2つのアプローチがあります。1つは、Cスタイルの文字列(文字列リテラル)を使用する方法で、もう1つは、std::string クラスを使用する方法です。

文字列リテラルは、ダブルクォートで囲まれた文字の集合です。例えば、以下のように定義されます:

const char* cstr = "Hello, World!";

文字列リテラルはヌル終端(\0)されており、メモリ上で固定長の文字配列として扱われます。しかし、Cスタイルの文字列には直接メモリ操作やバッファオーバーフローのリスクが伴うため、安全性と柔軟性に欠ける場合があります。

一方、std::string オブジェクトは、C++標準ライブラリの一部として提供され、動的にサイズを変更できる文字列を扱うことができます。以下は、std::string の基本的な使用例です:

std::string str = "Hello, World!";

std::string クラスは、文字列の操作を容易にし、安全かつ効率的に行うための多くのメソッドを提供しています。

コンストラクタ

[編集]

std::string クラスには、文字列を初期化するための複数のコンストラクタが用意されています。これにより、様々な方法で文字列を生成することができます。

デフォルトコンストラクタ

[編集]

デフォルトコンストラクタは、空の文字列を作成します。以下のコードは、デフォルトコンストラクタを使用して空の std::string オブジェクトを作成する例です:

std::string s1;

この場合、s1 は空の文字列であり、サイズは0です。

文字列リテラルからのコンストラクタ

[編集]

文字列リテラルから std::string オブジェクトを作成するコンストラクタです。これは、Cスタイルの文字列をC++の std::string に変換する際に便利です。

std::string s2 = "Hello, World!";

この場合、s2"Hello, World!" という文字列を保持します。

コピーコンストラクタ

[編集]

コピーコンストラクタは、既存の std::string オブジェクトから新しい std::string オブジェクトを作成します。

std::string s3 = s2;

この場合、s3s2 と同じ内容の文字列を保持します。コピーコンストラクタは、オリジナルの文字列を変更せずに新しい文字列を作成するのに有用です。

ムーブコンストラクタ

[編集]

ムーブコンストラクタは、リソースの所有権を既存の std::string オブジェクトから新しい std::string オブジェクトに移動させます。これにより、コピー操作よりも効率的にリソースを再利用することができます。

std::string s4 = std::move(s3);

この場合、s4s3 の内容を引き継ぎ、s3 は空の状態になります。ムーブコンストラクタは、パフォーマンスの最適化に役立ちます。

部分文字列からのコンストラクタ

[編集]

部分文字列から新しい std::string オブジェクトを作成するコンストラクタです。このコンストラクタを使用すると、既存の文字列の一部を基に新しい文字列を生成できます。

std::string s5(s2, 7, 5);

この場合、s5s2 の7文字目から始まる5文字分の部分文字列を保持します。すなわち、s5"World" という文字列になります。

std::stringリテラルからのコンストラクタ

[編集]

std::stringリテラルから新しい std::string オブジェクトを作成するコンストラクタです。このコンストラクタを使用すると、””の末尾に s がついたstd::stringリテラルを基に新しい文字列を生成できます。

using namespace std::string_literals; // std::stringリテラルを有効化
std::string s6 = "New world"s;

以上のように、std::string クラスのコンストラクタは、多様な方法で文字列を初期化するための強力なツールを提供しています。これにより、プログラマーは柔軟に文字列を操作し、効率的にコードを記述することができます。

文字列の操作

[編集]

文字列の結合(+ 演算子と append メソッド)

[編集]

C++の std::string クラスは、簡単に文字列を結合するための方法を提供しています。特に、+ 演算子と append メソッドを使用することが一般的です。

+ 演算子

[編集]

+ 演算子を使用することで、2つの std::string オブジェクトまたは std::string オブジェクトと文字列リテラルを結合できます。

std::string str1 = "Hello, ";
std::string str2 = "World!";
std::string result = str1 + str2;

この場合、result"Hello, World!" になります。また、文字列リテラルとも結合可能です。

std::string greeting = "Hello, " + std::string("World!");

append メソッド

[編集]

append メソッドは、既存の std::string オブジェクトに対して文字列を追加するメソッドです。

std::string str1 = "Hello, ";
str1.append("World!");

この場合、str1"Hello, World!" になります。また、部分文字列を追加することもできます。

std::string str = "Hello";
str.append(" C++ World!", 4, 6); // " C++ World!" の4文字目から6文字分を追加

この場合、str"HelloWorld" になります。

部分文字列の取得(substr メソッド)

[編集]

std::string クラスの substr メソッドを使用すると、元の文字列から部分文字列を抽出できます。

std::string str = "Hello, World!";
std::string sub = str.substr(7, 5); // 7文字目から5文字分の部分文字列を取得

この場合、sub"World" になります。substr メソッドの第一引数は開始位置、第二引数は長さを指定します。第二引数を省略すると、開始位置から末尾までの文字列を取得します。

std::string sub2 = str.substr(7); // "World!"

文字のアクセス(at メソッドと operator[])

[編集]

std::string クラスでは、特定の位置にある文字にアクセスする方法として at メソッドと operator[] を提供しています。

at メソッド

[編集]

at メソッドは、指定した位置の文字を返します。範囲外の位置を指定すると、例外(std::out_of_range)がスローされます。

std::string str = "Hello";
char c = str.at(1); // 'e'

operator[]

[編集]

operator[] も指定した位置の文字を返しますが、範囲外の位置を指定した場合の動作は未定義です。

char c = str[1]; // 'e'

operator[] は範囲チェックを行わないため、速度面で若干の利点がありますが、使用には注意が必要です。

文字列の長さと容量(length, size, capacity, resize, reserve メソッド)

[編集]

std::string クラスは、文字列の長さと容量を管理するための複数のメソッドを提供しています。

length と size

[編集]

length メソッドと size メソッドは、文字列の長さ(文字数)を返します。これらは同義であり、どちらを使用しても同じ結果を得られます。

std::string str = "Hello";
size_t len = str.length(); // 5
size_t size = str.size();  // 5

capacity

[編集]

capacity メソッドは、現在の文字列が再割り当てなしに格納できる最大の文字数を返します。これは、性能を最適化するために使用されることがあります。

size_t cap = str.capacity();

resize

[編集]

resize メソッドは、文字列の長さを変更します。新しい長さが現在の長さより短い場合、文字列は切り詰められます。新しい長さが現在の長さより長い場合、追加された部分はデフォルトではヌル文字で埋められますが、指定された文字で埋めることも可能です。

str.resize(10); // "Hello\0\0\0\0\0"
str.resize(15, 'x'); // "Hello\0\0\0\0\0xxxxx"

reserve

[編集]

reserve メソッドは、将来の成長を考慮して、文字列の容量をあらかじめ確保します。これにより、頻繁な再割り当てを防ぎ、パフォーマンスを向上させることができます。

str.reserve(50); // 容量を50に設定

これらのメソッドを組み合わせて使用することで、std::string オブジェクトの操作を効率的かつ柔軟に行うことができます。

文字列の比較

[編集]

C++の std::string クラスは、文字列の比較を簡単に行うための多くの機能を提供しています。特に、比較演算子と compare メソッドがよく使用されます。

比較演算子(==, !=, <, >, <=, >=)

[編集]

C++では、std::string クラスのインスタンス間で比較を行うために、標準の比較演算子を使用できます。これらの演算子を使用することで、文字列の等価性や大小関係を簡単に評価できます。

== 演算子

[編集]

== 演算子は、2つの std::string オブジェクトが等しいかどうかを比較します。

std::string str1 = "Hello";
std::string str2 = "Hello";
if (str1 == str2) {
    // 条件が真
}

この場合、str1str2 は同じ内容の文字列を保持しているため、条件は真となります。

!= 演算子

[編集]

!= 演算子は、2つの std::string オブジェクトが等しくないかどうかを比較します。

if (str1 != str2) {
    // 条件が偽
}

この場合、str1str2 は同じ内容の文字列を保持しているため、条件は偽となります。

<, >, <=, >= 演算子

[編集]

これらの演算子は、辞書式順序に基づいて文字列の大小関係を比較します。

std::string str3 = "Apple";
std::string str4 = "Banana";
if (str3 < str4) {
    // 条件が真
}

この場合、"Apple" は辞書式順序で "Banana" より前に来るため、条件は真となります。

同様に、>, <=, >= を使用して文字列の順序を比較できます。

if (str3 > str4) {
    // 条件が偽
}
if (str3 <= str4) {
    // 条件が真
}
if (str3 >= str4) {
    // 条件が偽
}

compare メソッド

[編集]

std::string クラスの compare メソッドは、より詳細な比較を行うための機能を提供します。compare メソッドは、比較結果を整数値で返します。

  • 0:等しい
  • 正の値:左側の文字列が辞書式順序で後に位置する
  • 負の値:左側の文字列が辞書式順序で前に位置する

基本的な compare メソッド

[編集]

2つの std::string オブジェクトを比較する基本的な方法です。

int result = str1.compare(str2);
if (result == 0) {
    // str1 と str2 は等しい
} else if (result < 0) {
    // str1 は str2 よりも前に位置する
} else {
    // str1 は str2 よりも後に位置する
}

部分文字列の比較

[編集]

compare メソッドは、部分文字列同士の比較も行うことができます。以下の例では、str3 の0文字目から5文字分と str4 を比較します。

int result = str3.compare(0, 5, str4);
if (result == 0) {
    // str3 の最初の5文字と str4 は等しい
}

文字数指定の比較

[編集]

さらに、比較する文字数を指定することもできます。

std::string str5 = "Hello, World!";
std::string str6 = "Hello, Everyone!";
int result = str5.compare(0, 5, str6, 0, 5);
if (result == 0) {
    // str5 の最初の5文字と str6 の最初の5文字は等しい
}

このように、std::string クラスの比較演算子と compare メソッドを使用することで、文字列の等価性や大小関係を柔軟かつ効率的に評価することができます。用途に応じてこれらの機能を使い分けることで、文字列比較に関する様々な要件に対応することができます。

文字列の検索

[編集]

C++の std::string クラスは、文字列内で部分文字列を検索するための多様なメソッドを提供しています。特に、findrfindfind_first_offind_last_of メソッドを使用することで、効率的に部分文字列を見つけることができます。また、部分文字列の削除や置換を行うための erasereplace メソッドも用意されています。

部分文字列の検索(find, rfind, find_first_of, find_last_of)

[編集]

find メソッド

[編集]

find メソッドは、文字列内で指定した部分文字列が最初に現れる位置を返します。見つからない場合は std::string::npos を返します。

std::string str = "Hello, World!";
size_t pos = str.find("World");
if (pos != std::string::npos) {
    // "World" は位置 pos に存在する
}

rfind メソッド

[編集]

rfind メソッドは、文字列内で指定した部分文字列が最後に現れる位置を返します。見つからない場合は std::string::npos を返します。

std::string str = "Hello, World! World!";
size_t pos = str.rfind("World");
if (pos != std::string::npos) {
    // "World" は最後に位置 pos に存在する
}

find_first_of メソッド

[編集]

find_first_of メソッドは、文字列内で指定した文字集合のいずれかが最初に現れる位置を返します。見つからない場合は std::string::npos を返します。

std::string str = "Hello, World!";
size_t pos = str.find_first_of("aeiou");
if (pos != std::string::npos) {
    // 最初の母音は位置 pos に存在する
}

find_last_of メソッド

[編集]

find_last_of メソッドは、文字列内で指定した文字集合のいずれかが最後に現れる位置を返します。見つからない場合は std::string::npos を返します。

std::string str = "Hello, World!";
size_t pos = str.find_last_of("aeiou");
if (pos != std::string::npos) {
    // 最後の母音は位置 pos に存在する
}

部分文字列の削除と置換(erase, replace メソッド)

[編集]

erase メソッド

[編集]

erase メソッドは、文字列の一部を削除するために使用されます。削除する範囲を指定することで、その部分文字列を削除します。

std::string str = "Hello, World!";
str.erase(5, 7); // "Hello"

この例では、5文字目から7文字分を削除しています。

replace メソッド

[編集]

replace メソッドは、文字列の一部を別の文字列で置換するために使用されます。置換する範囲と置換する文字列を指定します。

std::string str = "Hello, World!";
str.replace(7, 5, "Universe"); // "Hello, Universe!"

この例では、7文字目から5文字分を "Universe" に置換しています。

さらに、部分文字列を検索してから置換することも一般的です。

std::string str = "Hello, World!";
size_t pos = str.find("World");
if (pos != std::string::npos) {
    str.replace(pos, 5, "Universe"); // "Hello, Universe!"
}

このように、std::string クラスの検索と操作メソッドを組み合わせることで、文字列内の特定の部分文字列を効率的に検索し、必要に応じて削除や置換を行うことができます。これらのメソッドを活用することで、文字列操作を柔軟に行うことができます。

文字列の変換

[編集]

C++では、数値と文字列の間で変換を行うために、標準ライブラリが提供する便利な関数があります。これにより、数値を文字列に変換したり、文字列を数値に変換したりすることが容易にできます。

数値から文字列への変換(std::to_string)

[編集]

std::to_string 関数は、数値型の値を文字列に変換するための関数です。整数型、浮動小数点型など、様々な数値型に対応しています。

使用例

[編集]

以下の例は、整数、浮動小数点数、長整数を文字列に変換する方法を示しています。

#include <string>
#include <iostream>

auto main() -> int {
    int i = 42;
    double d = 3.14159;
    long l = 1234567890;

    std::string str1 = std::to_string(i); // "42"
    std::string str2 = std::to_string(d); // "3.141590"
    std::string str3 = std::to_string(l); // "1234567890"

    std::cout << "Integer: " << str1 << std::endl;
    std::cout << "Double: " << str2 << std::endl;
    std::cout << "Long: " << str3 << std::endl;

    return 0;
}

std::to_string を使用することで、簡単に数値を文字列に変換できます。変換された文字列は、様々な出力形式で利用できます。

文字列から数値への変換(std::stoi, std::stol, std::stod など)

[編集]

std::stoi, std::stol, std::stod などの関数は、文字列を数値に変換するための標準ライブラリ関数です。これらの関数は、文字列の内容を適切な数値型に変換します。

std::stoi

[編集]

std::stoi 関数は、文字列を整数に変換します。

#include <string>
#include <iostream>

auto main() -> int {
    std::string str = "42";
    int num = std::stoi(str); // 42

    std::cout << "String to int: " << num << std::endl;

    return 0;
}

std::stol

[編集]

std::stol 関数は、文字列を長整数に変換します。

#include <string>
#include <iostream>

auto main() -> int {
    std::string str = "1234567890";
    long num = std::stol(str); // 1234567890

    std::cout << "String to long: " << num << std::endl;

    return 0;
}

std::stod

[編集]

std::stod 関数は、文字列を浮動小数点数に変換します。

#include <string>
#include <iostream>

auto main() -> int {
    std::string str = "3.14159";
    double num = std::stod(str); // 3.14159

    std::cout << "String to double: " << num << std::endl;

    return 0;
}

例外処理

[編集]

文字列を数値に変換する際に、無効な入力が含まれている場合、これらの関数は std::invalid_argument または std::out_of_range 例外をスローします。これにより、エラー処理を行うことができます。

#include <string>
#include <iostream>
#include <exception>

auto main() -> int {
    std::string str = "invalid";

    try {
        int num = std::stoi(str); // 例外がスローされる
    } catch (const std::invalid_argument& e) {
        std::cout << "Invalid argument: " << e.what() << std::endl;
    } catch (const std::out_of_range& e) {
        std::cout << "Out of range: " << e.what() << std::endl;
    }

    return 0;
}

このように、C++の標準ライブラリを使用することで、数値と文字列の間の変換を簡単に行うことができます。適切なエラー処理を行うことで、安全かつ信頼性の高いプログラムを作成することが可能です。

入出力

[編集]

標準入力からの読み取り(std::cin)

[編集]

標準出力への書き込み(std::cout)

[編集]

ファイル入出力での使用例

[編集]

入出力

[編集]

C++では、標準ライブラリを使用して標準入力・出力、ファイル入出力を効率的に行うことができます。以下では、標準入力からの読み取り、標準出力への書き込み、そしてファイル入出力の使用例について説明します。

標準入力からの読み取り(std::cin)

[編集]

std::cin は、標準入力(通常はキーボード)からデータを読み取るためのストリームです。ユーザーからの入力をプログラム内で処理する際に使用します。

基本的な使用例

[編集]
#include <iostream>
#include <string>

auto main() -> int {
    std::string name;
    int age;

    std::cout << "Enter your name: ";
    std::cin >> name; // 文字列の入力を読み取る

    std::cout << "Enter your age: ";
    std::cin >> age; // 整数の入力を読み取る

    std::cout << "Name: " << name << ", Age: " << age << std::endl;

    return 0;
}

getline 関数を使用した読み取り

[編集]

std::cin では、空白を含む文字列を読み取るために getline 関数を使用することも一般的です。

#include <iostream>
#include <string>

auto main() -> int {
    std::string fullName;

    std::cout << "Enter your full name: ";
    std::getline(std::cin, fullName); // 行全体を読み取る

    std::cout << "Full Name: " << fullName << std::endl;

    return 0;
}

標準出力への書き込み(std::cout)

[編集]

std::cout は、標準出力(通常はコンソール)にデータを出力するためのストリームです。

基本的な使用例

[編集]
#include <iostream>

auto main() -> int {
    std::cout << "Hello, World!" << std::endl; // 文字列の出力
    int num = 42;
    std::cout << "The answer is " << num << std::endl; // 変数の出力

    return 0;
}

ファイル入出力での使用例

[編集]

C++では、ファイルからデータを読み取ったり、ファイルにデータを書き込んだりするために、<fstream> ヘッダーに定義されている std::ifstreamstd::ofstream クラスを使用します。

ファイルへの書き込み

[編集]
#include <fstream>
#include <iostream>

auto main() -> int {
    std::ofstream outFile("output.txt");

    if (!outFile) {
        std::cerr << "Error opening file for writing" << std::endl;
        return 1;
    }

    outFile << "Hello, file!" << std::endl;
    outFile << "The answer is " << 42 << std::endl;

    outFile.close(); // ファイルを閉じる

    return 0;
}

ファイルからの読み取り

[編集]
#include <fstream>
#include <iostream>
#include <string>

auto main() -> int {
    std::ifstream inFile("input.txt");

    if (!inFile) {
        std::cerr << "Error opening file for reading" << std::endl;
        return 1;
    }

    std::string line;
    while (std::getline(inFile, line)) {
        std::cout << line << std::endl; // ファイルから読み取った行を出力
    }

    inFile.close(); // ファイルを閉じる

    return 0;
}

ファイル入出力のまとめ

[編集]

ファイル入出力を行う際には、ファイルのオープンに失敗した場合のエラーチェックを行うことが重要です。また、読み取りや書き込みが終わったらファイルを閉じることも忘れないようにしましょう。

これらの基本操作を組み合わせることで、C++プログラム内で効率的な入出力処理を行うことができます。標準入力・出力とファイル入出力を適切に活用することで、プログラムの汎用性と実用性を高めることができます。

文字列の操作に関するアルゴリズム

[編集]

C++の標準ライブラリには、文字列の操作に関する強力なアルゴリズムが多数用意されています。これらのアルゴリズムを使用することで、文字列のソートや検索、変換などの操作を効率的に行うことができます。

文字列のソート(std::sort を使った例)

[編集]

std::sort 関数を使用して、文字列の文字をアルファベット順にソートすることができます。std::sort<algorithm> ヘッダーに定義されており、範囲ベースのアルゴリズムです。

使用例

[編集]
#include <algorithm>
#include <iostream>
#include <string>

auto main() -> int {
    std::string str = "hello";
    
    std::sort(str.begin(), str.end()); // 文字列をソート
    
    std::cout << "Sorted string: " << str << std::endl; // "Sorted string: ehllo"
    
    return 0;
}

この例では、std::sort を使用して "hello""ehllo" にソートしています。str.begin()str.end() は文字列の先頭と末尾を指すイテレータです。

文字列の検索(std::find, std::search)

[編集]

std::findstd::search は、文字列やシーケンス内で特定の要素やサブシーケンスを検索するためのアルゴリズムです。

std::find

[編集]

std::find は、指定された範囲内で特定の値を検索します。見つかった場合、その要素を指すイテレータを返し、見つからなかった場合は範囲の終端を指すイテレータを返します。

#include <algorithm>
#include <iostream>
#include <string>

auto main() -> int {
    std::string str = "hello world";
    char target = 'o';
    
    auto it = std::find(str.begin(), str.end(), target);
    
    if (it != str.end()) {
        std::cout << "Found '" << target << "' at position " << std::distance(str.begin(), it) << std::endl;
    } else {
        std::cout << "'" << target << "' not found" << std::endl;
    }
    
    return 0;
}

この例では、std::find を使用して文字 'o' を検索し、見つかった位置を出力しています。

std::search

[編集]

std::search は、指定された範囲内でサブシーケンス(部分文字列)を検索します。見つかった場合、そのサブシーケンスの開始位置を指すイテレータを返し、見つからなかった場合は範囲の終端を指すイテレータを返します。

#include <algorithm>
#include <iostream>
#include <string>

auto main() -> int {
    std::string str = "hello world";
    std::string target = "world";
    
    auto it = std::search(str.begin(), str.end(), target.begin(), target.end());
    
    if (it != str.end()) {
        std::cout << "Found \"" << target << "\" at position " << std::distance(str.begin(), it) << std::endl;
    } else {
        std::cout << "\"" << target << "\" not found" << std::endl;
    }
    
    return 0;
}

この例では、std::search を使用して部分文字列 "world" を検索し、見つかった位置を出力しています。

文字列の変換(std::transform)

[編集]

std::transform は、指定された範囲内の各要素に対して変換を適用し、その結果を別の範囲に格納するアルゴリズムです。大文字と小文字の変換など、文字列の要素ごとの変換に使用されます。

使用例

[編集]

以下の例では、文字列を大文字に変換します。

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>

auto main() -> int {
    std::string str = "hello world";
    
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
    
    std::cout << "Uppercase string: " << str << std::endl; // "HELLO WORLD"
    
    return 0;
}

この例では、std::transform を使用して各文字を toupper 関数で大文字に変換しています。変換された結果は同じ文字列 str に格納されます。

std::transform を使用して文字列を小文字に変換する場合も同様です。

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>

auto main() -> int {
    std::string str = "HELLO WORLD";
    
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    
    std::cout << "Lowercase string: " << str << std::endl; // "hello world"
    
    return 0;
}

このように、C++の標準ライブラリに用意されているアルゴリズムを活用することで、文字列の操作を簡単かつ効率的に行うことができます。これらのアルゴリズムは、文字列だけでなく、他のシーケンスコンテナにも適用可能な汎用性の高いツールです。

高度な使用方法

[編集]

C++における文字列操作の高度な使用方法として、カスタムメモリアロケータ、ムーブセマンティクスの活用、および std::string_view の紹介と使用例について説明します。

カスタムのメモリアロケータ

[編集]

C++の標準ライブラリでは、コンテナクラスに対してカスタムメモリアロケータを指定することができます。これにより、メモリ管理の方法を制御し、パフォーマンスの最適化や特殊なメモリ管理要件に対応することが可能です。std::string クラスも例外ではなく、カスタムアロケータを使用できます。

カスタムアロケータの例

[編集]

以下は、基本的なカスタムメモリアロケータの実装例です。このアロケータは、標準の std::allocator をベースにしています。

#include <iostream>
#include <string>
#include <memory>

template <typename T>
class CustomAllocator {
public:
    using value_type = T;

    CustomAllocator() = default;

    template <typename U>
    CustomAllocator(const CustomAllocator<U>&) {}

    T* allocate(std::size_t n) {
        std::cout << "Allocating " << n << " elements." << std::endl;
        return std::allocator<T>().allocate(n);
    }

    void deallocate(T* p, std::size_t n) {
        std::cout << "Deallocating " << n << " elements." << std::endl;
        std::allocator<T>().deallocate(p, n);
    }
};

template <typename T, typename U>
bool operator==(const CustomAllocator<T>&, const CustomAllocator<U>&) {
    return true;
}

template <typename T, typename U>
bool operator!=(const CustomAllocator<T>& a, const CustomAllocator<U>& b) {
    return !(a == b);
}

auto main() -> int {
    std::basic_string<char, std::char_traits<char>, CustomAllocator<char>> str("Hello, Custom Allocator!");
    std::cout << str << std::endl;

    return 0;
}

この例では、CustomAllocator クラスを定義し、std::basic_string を使用してカスタムアロケータを std::string に適用しています。メモリアロケーションとデアロケーションの際にメッセージを出力することで、カスタムアロケータの動作を確認できます。

ムーブセマンティクスの活用

[編集]

ムーブセマンティクスは、C++11で導入された機能であり、オブジェクトの所有権を効率的に移動することで、不要なコピーを回避し、パフォーマンスを向上させることができます。std::string クラスもムーブセマンティクスをサポートしています。

ムーブコンストラクタとムーブ代入演算子

[編集]

以下は、std::string に対するムーブセマンティクスの使用例です。

#include <iostream>
#include <string>

auto main() -> int {
    std::string str1 = "Hello, World!";
    std::string str2 = std::move(str1);

    std::cout << "str1: " << str1 << std::endl; // str1は空になる
    std::cout << "str2: " << str2 << std::endl; // "Hello, World!"

    std::string str3 = "Temporary string";
    str2 = std::move(str3);

    std::cout << "str2: " << str2 << std::endl; // "Temporary string"
    std::cout << "str3: " << str3 << std::endl; // str3は空になる

    return 0;
}

この例では、std::move を使用して文字列の所有権を移動させています。ムーブ後のオブジェクトは空の状態(もしくは未定義の状態)になりますが、所有権の移動によりパフォーマンスが向上します。

std::string_view の紹介と使用例

[編集]

std::string_view は、C++17で導入された非所有の文字列ビューであり、文字列リテラルや std::string などの文字列データを効率的に参照するためのクラスです。std::string_view を使用することで、文字列のコピーを伴わない軽量な文字列操作が可能になります。

基本的な使用例

[編集]
#include <iostream>
#include <string>
#include <string_view>

void printStringView(std::string_view sv) {
    std::cout << "String view: " << sv << std::endl;
}

auto main() -> int {
    std::string str = "Hello, string_view!";
    std::string_view sv1 = str;

    printStringView(sv1);

    const char* cstr = "Hello, C-string!";
    std::string_view sv2 = cstr;

    printStringView(sv2);

    return 0;
}

この例では、std::string_view を使用して、std::string やC文字列を参照しています。printStringView 関数に std::string_view を渡すことで、コピーのオーバーヘッドなしに文字列データを処理できます。

部分文字列の操作

[編集]

std::string_view を使用すると、部分文字列を簡単に操作できます。

#include <iostream>
#include <string_view>

auto main() -> int {
    std::string_view sv = "Hello, string_view!";
    
    std::string_view sv1 = sv.substr(0, 5); // "Hello"
    std::string_view sv2 = sv.substr(7, 6); // "string"

    std::cout << "First part: " << sv1 << std::endl;
    std::cout << "Second part: " << sv2 << std::endl;

    return 0;
}

この例では、std::string_view::substr メソッドを使用して部分文字列を取得しています。これにより、元の文字列データを変更せずに効率的に部分文字列を操作できます。

まとめ

C++の高度な文字列操作技術には、カスタムメモリアロケータ、ムーブセマンティクス、そして std::string_view の活用があります。これらの技術を駆使することで、パフォーマンスを最適化し、効率的な文字列操作を実現することができます。カスタムメモリアロケータは特殊なメモリ管理が必要な場合に有用であり、ムーブセマンティクスは不要なコピーを避けてパフォーマンスを向上させます。std::string_view は非所有の文字列参照を提供し、コピーのオーバーヘッドなしに文字列データを操作するのに役立ちます。

エンコーディング

[編集]

std::string は、C++の標準ライブラリで提供される文字列を表現するためのクラスですが、文字列のエンコーディングについては直接的に制約を持ちません。これは、std::string がバイト列を扱うため、文字列のエンコーディングはプログラマが文字列を処理する際に意識して制御する必要があるためです。

一方、エンコーディングを明示的に扱うことが必要な場合には、以下のような代替のクラスや機能を考慮することができます。

std::wstring
wchar_t を要素とするワイド文字列を表現するクラス。これはプラットフォームによって異なるサイズを持つことがあります。Windows環境ではUTF-16エンコーディングが一般的ですが、他のプラットフォームでは異なるエンコーディングを使用することもあります。
std::u16string
UTF-16エンコーディングを使用する文字列を表現するクラス。各文字は16ビットの符号単位で表されます。これは主にWindowsプラットフォームで使用されます。
std::u32string
UTF-32エンコーディングを使用する文字列を表現するクラス。各文字は32ビットの符号単位で表されます。これは、Unicodeの各コードポイントを1つの符号単位で表現するため、扱いやすく理解しやすいエンコーディングです。
std::wstring_convert
<locale> ヘッダーで提供される機能を使用して、異なるエンコーディング間で文字列を変換するためのクラス。ただし、C++17以降では非推奨となっています。
外部ライブラリ
一部の外部ライブラリ(例: ICU、Boost.Locale)は、Unicode文字列を効果的に処理するための高度な機能を提供します。これらのライブラリは、文字列の正規化、変換、検索などの操作を行うための便利な機能を提供します。

エンコーディングに関しては、プログラマが特定の環境やアプリケーションの要件に応じて適切なエンコーディングを選択し、適切な方法で処理する必要があります。また、異なるエンコーディング間での変換や、エンコーディングによる挙動の違いに注意する必要があります。

例題と演習問題

[編集]

基本的な文字列操作の練習問題

[編集]
  1. 文字列の長さを計算するプログラムを作成してください。
  2. 文字列を逆順にするプログラムを作成してください。
  3. 文字列内の大文字を小文字に、小文字を大文字に変換するプログラムを作成してください。
  4. 文字列内の特定の文字を別の文字に置換するプログラムを作成してください。
  5. 与えられた文字列が回文(前から読んでも後ろから読んでも同じ)であるかどうかを判定するプログラムを作成してください。

応用的な文字列操作の演習問題

[編集]
  1. 文字列内の単語を逆順にするプログラムを作成してください。例えば、"Hello World" は "World Hello" になります。
  2. 与えられた2つの文字列がアナグラム(同じ文字を含むが順序が異なる)であるかどうかを判定するプログラムを作成してください。
  3. 与えられた文字列が他の文字列の部分文字列であるかどうかを判定するプログラムを作成してください。
  4. 与えられた文字列内のすべての重複した文字を削除するプログラムを作成してください。
  5. 文字列をトークンに分割し、各トークンの出現回数をカウントするプログラムを作成してください。

実際のアプリケーションでの文字列操作の例題

[編集]
  1. テキストファイル内の単語の出現頻度を計算するプログラムを作成してください。
  2. 文字列内のURLを検出し、それらのURLをクリック可能なリンクに変換するプログラムを作成してください。
  3. ユーザーからの入力された電子メールアドレスが有効であるかどうかを検証するプログラムを作成してください。
  4. 文字列内の日付を検出し、日付の書式を変更するプログラムを作成してください。
  5. 文字列内の数字の合計を計算するプログラムを作成してください。

これらの例題と演習問題は、文字列操作に関する基本的な理解を深めるだけでなく、実際の問題に対するソリューションを考えるための練習として役立ちます。それぞれの問題を解く際には、標準ライブラリの文字列操作関数やアルゴリズムを駆使し、効率的で正確な解法を目指してください。

まとめと補足

[編集]

重要なポイントのまとめ

[編集]
  • C++の標準ライブラリには、<string> ヘッダーが含まれており、文字列操作に必要な機能を提供しています。
  • std::string クラスは、可変長の文字列を表現し、様々な文字列操作をサポートしています。
  • 文字列操作には、文字列の結合、分割、検索、置換、変換などが含まれます。
  • ムーブセマンティクスを活用することで、文字列の効率的な移動が可能となります。
  • std::string_view を使用すると、文字列の参照を効率的に扱うことができます。

参考文献とさらなる学習リソース

[編集]
  1. C++ String Class - cppreference.com における std::string の詳細なドキュメント。
  2. C++ String View - cppreference.com における std::string_view の詳細なドキュメント。
  3. Stroustrup, B. (2013). The C++ Programming Language (4th Edition). Addison-Wesley Professional.
  4. Josuttis, N. M. (2012). The C++ Standard Library: A Tutorial and Reference (2nd Edition). Addison-Wesley Professional.
  5. Meyers, S. (2014). Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14. O'Reilly Media.

これらの参考文献や学習リソースを活用することで、C++における文字列操作に関する理解を深めることができます。また、オンラインのコミュニティやフォーラムでのディスカッションに参加することも、学習の助けとなるでしょう。

附録

[編集]

<string> に含まれるすべてのメソッドとメンバ関数のリファレンス

[編集]

以下は、<string> ヘッダーに含まれる主要なメソッドとメンバ関数のリファレンスです。

std::string::string()
デフォルトコンストラクタ
std::string::string(const char*)
C文字列からのコンストラクタ
std::string::string(const std::string&)
コピーコンストラクタ
std::string::string(std::string&&)
ムーブコンストラクタ
std::string::string(size_t, char)
指定された長さと文字で初期化するコンストラクタ
std::string::operator=(const char*)
C文字列からの代入演算子
std::string::operator=(const std::string&)
コピー代入演算子
std::string::operator=(std::string&&)
ムーブ代入演算子
std::string::operator+=(const char*)
C文字列の連結演算子
std::string::operator+=(const std::string&)
文字列の連結演算子
std::string::operator+=(char)
文字の追加演算子
std::string::append(const char*)
C文字列の追加
std::string::append(const std::string&)
文字列の追加
std::string::append(size_t, char)
指定された長さと文字の追加
std::string::length(), std::string::size()
文字列の長さ
std::string::clear()
文字列のクリア
std::string::erase(size_t pos, size_t len)
指定された位置から指定された長さの文字列の削除
std::string::insert(size_t pos, const char*)
指定された位置にC文字列を挿入
std::string::replace(size_t pos, size_t len, const char*)
指定された範囲の文字列を置換
std::string::substr(size_t pos, size_t len)
部分文字列の取得
std::string::find(const char*), std::string::find(const std::string&)
文字列の検索
std::string::rfind(const char*), std::string::rfind(const std::string&)
逆方向からの文字列の検索
std::string::compare(const char*), std::string::compare(const std::string&)
文字列の比較

便利なヘルパー関数のリストとその使用例

[編集]

以下は、文字列操作に役立ついくつかの便利なヘルパー関数とその使用例です。

  1. std::to_string: 数値を文字列に変換する関数。
        int num = 42;
        std::string str = std::to_string(num);
    
  2. std::stoi, std::stol, std::stod: 文字列を数値に変換する関数。
        std::string str = "42";
        int num = std::stoi(str);
    
  3. std::getline: 入力ストリームから行を読み取る関数。
        std::string line;
        std::getline(std::cin, line);
    
  4. std::transform: コンテナ内の要素に変換を適用する関数。
        std::string str = "Hello";
        std::transform(str.begin(), str.end(), str.begin(), ::toupper);
    

これらのヘルパー関数を活用することで、より効率的で簡潔な文字列操作コードを記述することができます。