文字列

テキストデータの効率的な管理。std::string の使い方

概要

C++で文字列を扱う方法は大きく分けて2つあります:

  • C形式:char arr[] = "Hello";(文字配列)
  • C++形式:std::string str = "Hello";(推奨)

この章では、modern C++で標準的な std::stringクラスを学びます。

std::string の基本

宣言と初期化

#include <iostream>
#include <string>

int main() {
    std::string empty;              // 空の文字列
    std::string hello = "Hello";    // 初期化
    std::string world("World");     // 別の書き方
    std::string copies(5, '*');     // 5個の'*'で初期化 "****"
    
    std::cout << hello << std::endl;
    std::cout << world << std::endl;
    std::cout << copies << std::endl;
    
    return 0;
}

Hello
World
*****

文字列操作

連結(+演算子)

#include <iostream>
#include <string>

int main() {
    std::string first = "Hello";
    std::string second = "World";
    
    std::string result = first + ", " + second + "!";
    std::cout << result << std::endl;
    
    return 0;
}

Hello, World!

長さ(length() / size())

#include <iostream>
#include <string>

int main() {
    std::string text = "C++ Programming";
    
    std::cout << "長さ: " << text.length() << std::endl;
    std::cout << "サイズ: " << text.size() << std::endl;
    
    return 0;
}

長さ: 15
サイズ: 15

インデックスアクセス

std::string text = "Hello";

std::cout << text[0] << std::endl;  // 'H'
std::cout << text[1] << std::endl;  // 'e'

text[0] = 'J';
std::cout << text << std::endl;     // "Jello"

文字列の部分操作

部分文字列(substr)

#include <iostream>
#include <string>

int main() {
    std::string text = "C++ Programming";
    
    std::string part1 = text.substr(0, 3);    // インデックス0から3文字 "C++"
    std::string part2 = text.substr(4);       // インデックス4から最後まで "Programming"
    
    std::cout << part1 << std::endl;
    std::cout << part2 << std::endl;
    
    return 0;
}

C++
Programming

検索(find)

#include <iostream>
#include <string>

int main() {
    std::string text = "Hello World";
    
    size_t pos = text.find("World");
    
    if (pos != std::string::npos) {
        std::cout << "見つかった位置: " << pos << std::endl;
    } else {
        std::cout << "見つかりません" << std::endl;
    }
    
    return 0;
}

見つかった位置: 6

std::string::nposは「見つからない」を表すdinal値です。

文字列の追加と削除

追加(push_back、append)

#include <iostream>
#include <string>

int main() {
    std::string text = "Hello";
    
    text.push_back('!');           // 1文字追加
    std::cout << text << std::endl; // "Hello!"
    
    text.append(" World");         // 複数文字追加
    std::cout << text << std::endl; // "Hello! World"
    
    return 0;
}

Hello!
Hello! World

削除(pop_back、erase)

#include <iostream>
#include <string>

int main() {
    std::string text = "Hello World";
    
    text.pop_back();              // 最後の文字を削除
    std::cout << text << std::endl; // "Hello Worl"
    
    text.erase(5);                // インデックス5以降を削除
    std::cout << text << std::endl; // "Hello"
    
    return 0;
}

Hello Worl
Hello

文字列の反復処理

例1: 各文字を出力

#include <iostream>
#include <string>

int main() {
    std::string text = "C++";
    
    // 範囲ベースの for ループ
    for (char c : text) {
        std::cout << c << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

C + +

例2: 文字数を数える

#include <iostream>
#include <string>

int main() {
    std::string text = "programming";
    
    int count = 0;
    for (char c : text) {
        if (c == 'p') {
            count++;
        }
    }
    
    std::cout << "'p'の個数: " << count << std::endl;
    
    return 0;
}

'p'の個数: 2

実践例

例1: メールアドレスの検証

#include <iostream>
#include <string>

bool isValidEmail(const std::string & email) {
    size_t at_pos = email.find('@');
    if (at_pos == std::string::npos) return false;
    
    size_t dot_pos = email.find('.', at_pos);
    if (dot_pos == std::string::npos) return false;
    
    return (at_pos > 0) && (dot_pos > at_pos + 1) && (dot_pos < email.length() - 1);
}

int main() {
    std::string email1 = "user@example.com";
    std::string email2 = "invalid-email";
    
    std::cout << (isValidEmail(email1) ? "有効" : "無効") << std::endl;
    std::cout << (isValidEmail(email2) ? "有効" : "無効") << std::endl;
    
    return 0;
}

有効
無効

例2: 文字列の反転

#include <iostream>
#include <string>

int main() {
    std::string original = "Hello World";
    std::string reversed = original;
    
    std::reverse(reversed.begin(), reversed.end());
    
    std::cout << "元の文字列: " << original << std::endl;
    std::cout << "反転後: " << reversed << std::endl;
    
    return 0;
}

元の文字列: Hello World
反転後: dlroW olleH

文字列と数値の相互変換

#include <iostream>
#include <string>

int main() {
    // 文字列 → 数値
    std::string str1 = "42";
    int num1 = std::stoi(str1);  // stoi: string to int
    
    std::string str2 = "3.14";
    double num2 = std::stod(str2);  // stod: string to double
    
    std::cout << num1 * 2 << std::endl;    // 84
    std::cout << num2 * 2 << std::endl;   // 6.28
    
    // 数値 → 文字列
    int value = 123;
    std::string str3 = std::to_string(value);
    std::cout << "数値: " << str3 << std::endl;
    
    return 0;
}

84
6.28
数値: 123

ポイント

  • std::stringは安全で使いやすい文字列クラス
  • +演算子で簡単に連結
  • length()substr()find()などのメソッドが豊富
  • 範囲ベースの for ループで各文字に簡単アクセス
  • 数値との相互変換はstd::stoi/std::to_stringを使用

よくある誤り

誤り1: インデックスを範囲外

std::string text = "Hello";
std::cout << text[10] << std::endl;  // 危険!: 範囲外

誤り2: find()の戻り値をチェック忘れ

std::string text = "Hello";
size_t pos = text.find("x");
// npos チェックなしで pos を使用する
std::string sub = text.substr(pos);  // 危険!

誤り3: C形式文字列との混同

std::string str = "Hello";
const char* c_str = str.c_str();  // OK
// ただし c_str はポインタなので注意が必要

やってみよう

練習1: ユーザーから文字列を入力させ、その長さを表示。

練習2: 文字列内の特定の文字をカウントする関数。

練習3: 文字列を逆順にするプログラム。

チャレンジ: 回文判定プログラム(例:"racecar")。

まとめ

  • std::stringは modern C++の標準
  • 豊富なメンバー関数で効率的に文字列操作
  • 配列と異なり、サイズを動的に変更可能
  • 安全性と使いやすさで C形式文字列に優れる