HOWTO · C++
C++ で文字列をトリムする方法
この記事では、C++ で文字列をトリミングする方法を示します。
このページの内容
トリミングとは、文字列の先頭または末尾から指定した文字を取り除くことです。文字列の途中にある一致文字は取り除きません。標準の文字列検索関数でトリミング対象の文字を定め、erase で一致する範囲を削除します。以下の例では、元の std::string を直接変更します。
トリミングする文字を選ぶ
find_first_not_of と find_last_not_of に渡す引数は、個々の文字からなる集合です。各関数は、その集合に含まれない文字を検索します。引数は部分文字列でもパターンでもありません。たとえば、" ." は順序を問わず、半角スペースまたはピリオドを表します。スペースとピリオドが連続する2文字を表すわけではありません。
入力に合わせて文字の集合を選びます。半角スペースを指定すると、取り除かれるのは半角スペースだけです。空白文字の集合には、スペース、タブ、改行などを含められます。これらの検索関数が調べるのは char 要素です。そのため、バイト単位のトリミング対象文字だけでは、UTF-8テキストに含まれるすべてのUnicode空白文字を判定できません。
find_first_not_of と erase で左端をトリミングする
トリミング対象の集合に含まれない最初の文字を探し、それより前をeraseで削除します。この例では、左端にあるスペースとピリオドを取り除きます。単体で実行できるC++プログラムです。
次の例を実行します。コード内の表示ラベルと出力文字列は英語のままです。出力には C++ guide... と表示されます。
#include <iostream>
#include <string>
int main() {
std::string value = "...C++ guide...";
const std::string trim_chars = " .";
const std::string::size_type first = value.find_first_not_of(trim_chars);
value.erase(0, first);
std::cout << value << '\n';
}
C++ guide...
find_first_not_of は、集合に含まれない最初の文字のインデックスを返します。すべての文字が集合に含まれる場合、戻り値は std::string::npos です。その位置を erase(0, ...) の削除数として渡すと、文字列全体が削除されます。したがって、この例はトリミング対象の文字だけでできた文字列も処理できます。
find_last_not_of と erase で右端をトリミングする
右端を処理するには、トリミング対象の集合に含まれない最後の文字を後ろから検索し、その後ろにある末尾部分を削除します。find_last_not_of が返すのはインデックスなので、末尾部分の開始位置を得るには1を加えます。
この例のコード内の表示ラベルと出力文字列は英語のままです。出力には C++ guide と表示されます。
#include <iostream>
#include <string>
int main() {
std::string value = "C++ guide... ";
const std::string trim_chars = " .";
const std::string::size_type last = value.find_last_not_of(trim_chars);
if (last == std::string::npos) {
value.clear();
} else {
value.erase(last + 1);
}
std::cout << value << '\n';
}
C++ guide
集合に含まれない文字がない場合、find_last_not_of は std::string::npos を返すため、このチェックが必要です。この番兵値に1を加えると、符号なしの位置値が桁あふれします。トリミング対象の文字だけでできた入力は、文字列を空にして処理します。
両端をトリミングし、残る文字がない場合も処理する
両端をトリミングするには、集合に含まれない最初と最後の文字を見つけ、末尾部分と先頭部分をeraseで削除します。位置を計算する前に最初の検索結果を確認してください。結果が std::string::npos なら、残る文字はありません。この方法なら空の入力も安全に処理できます。
コード内の表示ラベルと出力文字列は英語のままです。出力には C++ guide と表示されます。
#include <iostream>
#include <string>
int main() {
std::string value = "...C++ guide...";
const std::string trim_chars = " .";
const std::string::size_type first = value.find_first_not_of(trim_chars);
if (first == std::string::npos) {
value.clear();
} else {
const std::string::size_type last = value.find_last_not_of(trim_chars);
value.erase(last + 1);
value.erase(0, first);
}
std::cout << value << '\n';
}
C++ guide
erase の呼び出しは value を変更し、トリミング済みのコピーを作るわけではありません。元の値を残す必要がある場合は、先にコピーを作り、そのコピーをトリミングします。std::string::npos は条件に合う文字が見つからないときの番兵値です。インデックスの計算に使う前に必ず確認してください。
空白文字または別の文字集合をトリミングする
文字の集合を変えれば、同じ方法で空白文字もトリミングできます。CおよびC++の文字処理で一般的に扱われる基本的な空白文字は、スペース、タブ、改行、復帰、フォームフィード、垂直タブの6種類です。" \t\n\r\f\v" のように指定します。この集合はこれらのバイト値を明示的に扱いますが、すべてのUnicode空白文字を網羅するものではありません。
たとえば、この文字列を上の左右いずれかの検索で trim_chars として使うと、端にある該当文字を取り除けます。データ形式でパディングがスペースとタブだけと定められている場合は、より狭い集合を使います。文字集合によるトリミングでは、端にある集合内の文字がそれぞれ取り除かれます。文字列の途中にある空白をまとめる操作とは異なります。空白の連続を正規表現で置換すると、途中の空白が変わる一方で端の空白が残ることもあるため、トリミングの代わりにはなりません。
プロジェクトですでにBoostを使っている場合は、String Algorithmsのドキュメントで、トリミングに使える任意のライブラリ機能を確認できます。プロジェクトで使用しているBoostのバージョンに対応するドキュメントを参照してください。上記の標準ライブラリの例に追加のライブラリは必要ありません。