【C++】Boostライブラリで文字列置換を簡単に実装する方法
C++ Boostではreplace_all
で全置換、replace_first
/replace_last
で部分置換、replace_all_copy
で元文字列を保持しつつコピー上で置換、regex_replace
で正規表現を使った置換が可能です。
これにより手早く柔軟な文字列操作が実現できます。
Boost.Algorithmを使った基本的な文字列置換
Boostライブラリのboost::algorithm
名前空間には、文字列の置換を簡単に行える便利な関数がいくつか用意されています。
これらの関数を理解しておくことで、C++のプログラム内で効率的に文字列の編集作業を行うことが可能です。
ここでは、代表的な置換関数であるreplace_all
、replace_all_copy
、replace_first
、replace_last
について詳しく解説します。
replace_all / replace_all_copy
関数シグネチャとパラメーター
boost::algorithm::replace_all
は、指定した文字列内のすべての一致箇所を一度に置換します。
関数の基本的なシグネチャは次の通りです。
namespace boost {
namespace algorithm {
void replace_all(std::string& s, const std::string& old_value, const std::string& new_value);
}
}
s
:置換対象の文字列。この文字列は関数呼び出し後に変更されるため、置換結果が反映されますold_value
:置換したい文字列のパターン。これに一致するすべての箇所が置換されますnew_value
:置換後の文字列
一方、replace_all_copy
は、元の文字列を変更せずに、新しい文字列を返します。
namespace boost {
namespace algorithm {
std::string replace_all_copy(const std::string& s, const std::string& old_value, const std::string& new_value);
}
}
s
:元の文字列。変更されません- 返り値:置換後の新しい文字列
これらの関数は、シンプルな置換処理に適しており、特に複数箇所の一括置換に便利です。
空文字列や重複パターンの扱い
replace_all
は、old_value
が空文字列の場合には何も置換しません。
これは、空文字列はすべての位置に一致するため、無限ループや予期しない動作を避けるためです。
また、old_value
が文字列内に複数回出現している場合でも、すべての一致箇所が一度に置換されます。
例えば、「Hello Hello Hello」という文字列に対してreplace_all
を適用すると、すべての”Hello”が置換され、結果は「Goodbye Goodbye Goodbye」になります。
ただし、old_value
が空文字列の場合は何も行われません。
したがって、置換対象の文字列が空文字列にならないように注意が必要です。
replace_first / replace_last
最初・最後の一致箇所だけ置換する動作
boost::algorithm::replace_first
は、文字列内の最初に一致した箇所だけを置換します。
シグネチャは次の通りです。
namespace boost {
namespace algorithm {
void replace_first(std::string& s, const std::string& old_value, const std::string& new_value);
}
}
s
:対象の文字列。関数呼び出し後に変更されますold_value
:置換したい文字列のパターンnew_value
:置換後の文字列
一方、replace_last
は文字列の最後に一致した箇所だけを置換します。
namespace boost {
namespace algorithm {
void replace_last(std::string& s, const std::string& old_value, const std::string& new_value);
}
}
これらの関数は、特定の位置だけを対象にした置換を行いたい場合に役立ちます。
コピー版との違い
replace_first
とreplace_last
は、いずれも対象の文字列を直接変更します。
一方、replace_all
とreplace_all_copy
は、前者が対象文字列を変更し、後者が新しい文字列を返す点で異なります。
また、replace_all
とreplace_all_copy
は複数箇所の置換に適しているのに対し、replace_first
とreplace_last
は、最初または最後の一致箇所だけを対象にした操作に特化しています。
これらの関数を適切に使い分けることで、文字列操作の効率化とコードの可読性向上につながります。
正規表現ベースの置換
boost::regex_replace
は、正規表現を用いて文字列の置換を行う関数です。
正規表現のパワーを活用することで、より複雑なパターンに対して柔軟に置換処理を実現できます。
ここでは、その構文と使い方、そしてキャプチャグループを利用した参照置換について詳しく解説します。
boost::regex_replaceの構文
基本的な使い方
boost::regex_replace
の基本的な構文は次の通りです。
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main() {
std::string str = "2023年4月15日";
boost::regex pattern("\\d+");
std::string result = boost::regex_replace(str, pattern, "X");
std::cout << result << std::endl; // 出力: XXX年X月X日
return 0;
}
X年X月X日
この例では、str
内のすべての数字にマッチする正規表現\\d+
を使い、boost::regex_replace
で数字部分を"X"
に置換しています。
boost::regex_replace
の関数シグネチャは次の通りです。
namespace boost {
namespace regex {
template <typename BidirectionalIterator, typename OutputIterator, typename Syntax, typename CharTraits, typename Allocator>
OutputIterator regex_replace(OutputIterator out, BidirectionalIterator first, BidirectionalIterator last,
const boost::basic_regex<CharTraits, Syntax>& e,
const CharT* fmt,
match_flag_type flags = match_default);
template <typename CharT, typename Traits, typename Allocator>
std::basic_string<CharT> regex_replace(const std::basic_string<CharT>& s,
const boost::basic_regex<CharT, Traits>& e,
const CharT* fmt,
match_flag_type flags = match_default);
}
}
最も一般的に使われるのは、後者のstd::string
を引数に取るバージョンです。
第3引数のfmt
は置換のパターンを示す文字列で、正規表現のキャプチャグループを参照して部分置換を行うことも可能です。
フラグ(ECMAScript/POSIX)設定例
boost::regex
のコンストラクタには、フラグを設定して正規表現の動作を制御できます。
代表的なフラグには次のようなものがあります。
boost::regex::ECMAScript
:ECMAScript標準の正規表現(デフォルト)boost::regex::POSIX
:POSIX標準の正規表現boost::regex::icase
:大文字・小文字を区別しないboost::regex::nosubs
:キャプチャグループの結果を保存しないboost::regex::optimize
:正規表現の最適化を行う
例として、フラグを設定して大文字・小文字を区別しない正規表現を作成し、置換を行うコードは次の通りです。
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main() {
std::string str = "abc ABC aBc";
boost::regex pattern("abc", boost::regex::icase | boost::regex::ECMAScript);
std::string result = boost::regex_replace(str, pattern, "XYZ");
std::cout << result << std::endl; // 出力: XYZ XYZ XYZ
return 0;
}
XYZ XYZ XYZ
この例では、"abc"
の大文字・小文字の違いに関わらず、すべて"XYZ"
に置換しています。
キャプチャグループと参照置換
正規表現のキャプチャグループを利用すると、置換パターン内でマッチした部分を再利用できます。
これにより、部分文字列の抽出や並び替えなど、柔軟な置換が可能となります。
グループ番号を使った部分置換
キャプチャグループは丸括弧()
で囲むことで定義します。
例えば、次の例では日付のフォーマットを変換します。
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main() {
std::string str = "2023-04-15";
boost::regex pattern("(\\d{4})-(\\d{2})-(\\d{2})");
// 置換パターン内でキャプチャグループを参照
std::string result = boost::regex_replace(str, pattern, "$3/$2/$1");
std::cout << result << std::endl; // 出力: 15/04/2023
return 0;
}
15/04/2023
ここでは、$1
は最初のキャプチャグループ(年)、$2
は月、$3
は日を表し、これらを並び替えて新しいフォーマットにしています。
名前付きキャプチャの利用
Boost.Regexは名前付きキャプチャもサポートしています。
次の例では、日付の各部分に名前を付けて、より読みやすくしています。
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main() {
std::string str = "2023-04-15";
boost::regex pattern("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})");
// 置換パターン内で名前付きキャプチャを参照
std::string result = boost::regex_replace(str, pattern, "${day}/${month}/${year}");
std::cout << result << std::endl; // 出力: 15/04/2023
return 0;
}
${day}/${month}/${year}
(?<name>...)
の形式でキャプチャグループに名前を付け、${name}
で参照します。
これにより、キャプチャグループの番号を覚える必要がなく、コードの可読性が向上します。
これらの機能を活用することで、正規表現を用いた高度な文字列置換を効率的に行うことが可能です。
複数パターン同時置換の実装例
複数の異なる文字列パターンを一度に置換したい場合、boost::algorithm
の標準関数だけでは対応が難しいことがあります。
そのため、std::map
を用いたパターンと置換文字列の対応表を作成し、ループ処理で逐次的に置換を行う方法や、Boost.Xpressiveの正規表現とコールバック機能を活用した条件付き置換の方法があります。
これらのアプローチを理解しておくと、複雑な置換処理も効率的に実装できます。
置換テーブル生成方法
複数のパターンと置換文字列を管理するために、std::map
を利用します。
キーに置換対象のパターン、値に置換後の文字列を格納します。
#include <map>
#include <string>
std::map<std::string, std::string> replacementTable = {
{"\\alpha", "a"},
{"\\beta", "b"},
{"\\gamma", "g"},
{"\\delta", "d"}
};
このように定義しておくと、後の処理でパターンごとにループして置換を行うことが容易になります。
ループ処理による逐次置換
std::map
に格納したパターンと置換文字列を使い、文字列全体に対して逐次的に置換を行います。
次の例では、入力文字列に対して、登録したすべてのパターンを順に置換しています。
#include <boost/algorithm/string/replace.hpp>
#include <iostream>
#include <string>
#include <map>
int main() {
std::string text = "\\alpha and \\beta are Greek letters. \\gamma is gamma.";
std::map<std::string, std::string> repTable = {
{"\\alpha", "a"},
{"\\beta", "b"},
{"\\gamma", "g"}
};
for (const auto& pair : repTable) {
boost::algorithm::replace_all(text, pair.first, pair.second);
}
std::cout << text << std::endl; // 出力: a and b are Greek letters. g is gamma.
return 0;
}
a and b are Greek letters. g is gamma.
この方法はシンプルでわかりやすく、パターン数が少ない場合や、置換の優先順位を制御したい場合に適しています。
ただし、パターンが多い場合や、パターンの重複・競合がある場合は、処理時間が増加する可能性があります。
Boost.Xpressiveで条件付き置換
Boost.Xpressiveは、正規表現とコールバックを組み合わせて、より高度な置換処理を実現します。
特に、複数のパターンに対して条件付きの置換や、パターンに応じた動的な処理を行いたい場合に有効です。
sregexの組み立て
sregex
は、複数のパターンを一つの正規表現にまとめることができ、キャプチャグループを使ってパターンを識別します。
#include <boost/xpressive/xpressive.hpp>
#include <iostream>
#include <string>
int main() {
using namespace boost::xpressive;
// 複数のパターンをまとめた正規表現
sregex pattern = (sregex::compile("\\\\alpha") | "\\\\beta" | "\\\\gamma");
std::string text = "\\alpha and \\beta and \\gamma";
// 置換結果を格納する文字列
std::string result;
// コールバック関数を使った置換
auto callback = [&](smatch const& m) {
if (m[0] == "\\alpha") return std::string("a");
if (m[0] == "\\beta") return std::string("b");
if (m[0] == "\\gamma") return std::string("g");
return std::string(m[0]);
};
// 置換処理
boost::xpressive::regex_replace(std::back_inserter(result), text.begin(), text.end(), pattern, callback);
std::cout << result << std::endl; // 出力: a and b and g
return 0;
}
a and \beta and \gamma
regex_actionsでのコールバック
boost::xpressive::regex_replace
は、コールバック関数を指定して、マッチした部分に対して動的に処理を行うことができます。
これにより、パターンごとに異なる置換処理や条件付きの置換を実現できます。
// main.cpp
#include <boost/xpressive/xpressive.hpp>
#include <iostream>
#include <string>
#include <iterator> // std::back_inserter
int main() {
using namespace boost::xpressive;
// \alpha, \beta, \gamma のいずれかにマッチし、
// alpha, beta, gamma をキャプチャする
sregex pattern = sregex::compile(R"(\\(alpha|beta|gamma))");
std::string text = R"(\alpha and \beta and \gamma)";
std::string result;
// コールバック:キャプチャした m[1] をそのまま返す
auto callback = [&](smatch const& m) {
return m[1].str();
};
// 置換実行
regex_replace(std::back_inserter(result),
text.begin(), text.end(),
pattern, callback);
std::cout << result << std::endl; // 出力: alpha and beta and gamma
return 0;
}
alpha and beta and gamma
このように、Boost.Xpressiveを使えば、複数パターンの一括置換だけでなく、条件に応じた動的な置換も容易に実現できます。
複雑な置換処理やパターンの優先順位制御が必要な場合に特に有効です。
実践サンプル
実際のアプリケーションでは、文字列の置換処理をファイル全体や特定のデータ形式に対して行うケースが多くあります。
ここでは、テキストファイルの一括置換、ログのマスキング処理、CSVデータの特定フィールド更新といった具体的な例を紹介します。
これらの例を通じて、実務で役立つ文字列置換の実装方法を理解します。
テキストファイル全体の一括置換
入出力ストリーム活用例
ファイル全体の置換処理は、標準の入出力ストリームを利用して効率的に行えます。
まず、入力ファイルを読み込み、出力ファイルに書き出す過程で、逐次的に文字列の置換を行います。
#include <fstream>
#include <sstream>
#include <string>
#include <boost/algorithm/string/replace.hpp>
int main() {
std::ifstream inputFile("input.txt");
std::ofstream outputFile("output.txt");
std::stringstream buffer;
// ファイル内容をバッファに読み込み
buffer << inputFile.rdbuf();
std::string content = buffer.str();
// 置換処理
boost::algorithm::replace_all(content, "古い文字列", "新しい文字列");
// 置換後の内容を出力ファイルに書き込み
outputFile << content;
return 0;
}
この例では、input.txt
の内容を一度メモリに読み込み、replace_all
で一括置換を行った後、output.txt
に書き出しています。
大きなファイルの場合は、逐次読み込みと書き込みを行う方法も検討します。
バッファ管理のポイント
大きなファイルを扱う場合、全内容を一度にメモリに読み込むとメモリ不足になる可能性があります。
そのため、一定サイズのバッファを使って逐次的に読み込み、部分ごとに置換処理を行う工夫が必要です。
また、std::stringstream
やstd::string
の操作はコストがかかるため、必要に応じてバッファサイズを調整し、効率的な処理を心がけます。
特に、複雑な置換や複数回の処理を行う場合は、パフォーマンスに注意しましょう。
ログマスキング処理
ログファイルには個人情報や機密情報が含まれることが多いため、公開前にIPアドレスやメールアドレスをマスキングする必要があります。
正規表現を用いて検出し、置換する方法を紹介します。
#include <boost/regex.hpp>
#include <fstream>
#include <string>
#include <sstream>
int main() {
std::ifstream logFile("log.txt");
std::stringstream buffer;
buffer << logFile.rdbuf();
std::string logContent = buffer.str();
// IPアドレスの正規表現
boost::regex ipRegex("(\\d{1,3}\\.){3}\\d{1,3}");
// メールアドレスの正規表現
boost::regex emailRegex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
// IPアドレスをマスキング
logContent = boost::regex_replace(logContent, ipRegex, "[IPマスク]");
// メールアドレスをマスキング
logContent = boost::regex_replace(logContent, emailRegex, "[メールマスク]");
std::ofstream maskedLogFile("masked_log.txt");
maskedLogFile << logContent;
return 0;
}
この例では、正規表現を使ってIPアドレスとメールアドレスを検出し、それぞれ"[IPマスク]"
と"[メールマスク]"
に置換しています。
これにより、個人情報の漏洩リスクを低減できます。
CSVデータの特定フィールド更新
CSVファイルの特定の列だけを更新したい場合、区切り文字(カンマ)を解析し、対象のフィールドだけを置換します。
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp>
int main() {
std::ifstream inputFile("data.csv");
std::ofstream outputFile("updated_data.csv");
std::string line;
while (std::getline(inputFile, line)) {
std::vector<std::string> fields;
boost::split(fields, line, boost::is_any_of(","));
// 例:3列目の値を置換
if (fields.size() >= 3) {
boost::replace_all(fields[2], "古い値", "新しい値");
}
// 更新後の行を再構築
std::string newLine = boost::join(fields, ",");
outputFile << newLine << "\n";
}
return 0;
}
この例では、boost::split
を使って行を区切り、対象の列だけをreplace_all
で置換しています。
最後にboost::join
で再びカンマ区切りの文字列に戻し、ファイルに書き出しています。
この方法は、CSVの構造を維持しつつ、特定のフィールドだけを効率的に更新できるため、データの整合性を保ちながら処理を行いたい場合に適しています。
Unicodeおよびワイド文字列への対応
C++で国際化や多言語対応を行う場合、Unicodeやワイド文字列の扱いは避けて通れません。
特に、日本語や中国語、韓国語などのマルチバイト文字を正しく処理するためには、標準のstd::string
だけでは不十分なケースがあります。
ここでは、std::wstring
を用いたワイド文字列の置換方法と、Boost.Regexのu32regex
を使ったマルチバイト対応の方法について解説します。
std::wstringでのreplace_all利用
std::wstring
は、ワイド文字wchar_t
を格納するための文字列型です。
これを使えば、Unicode文字列を扱うことが可能です。
ただし、boost::algorithm::replace_all
は標準ではstd::string
向けに設計されているため、std::wstring
に対しては、boost::algorithm::replace_all
のテンプレート特殊化や、boost::replace_all
のラッパー関数を自作する必要があります。
以下は、std::wstring
に対してreplace_all
を適用する例です。
#include <boost/algorithm/string/replace.hpp>
#include <string>
#include <iostream>
int main() {
std::wstring text = L"こんにちは、世界!こんにちは!";
// 置換対象の文字列と置換後の文字列
std::wstring target = L"こんにちは";
std::wstring replacement = L"やぁ";
// boost::replace_allはテンプレートの特殊化が必要なため、自作ラッパーを作成
auto replace_all_wstring = [](std::wstring& s, const std::wstring& old_value, const std::wstring& new_value) {
size_t start_pos = 0;
while ((start_pos = s.find(old_value, start_pos)) != std::wstring::npos) {
s.replace(start_pos, old_value.length(), new_value);
start_pos += new_value.length();
}
};
replace_all_wstring(text, target, replacement);
std::wcout << text << std::endl; // 出力: やぁ、世界!やぁ!
return 0;
}
この例では、std::wstring
に対してfind
とreplace
を用いて置換を行っています。
boost::algorithm
のreplace_all
はstd::string
専用のため、wstring
には自作のラッパー関数を作成して対応します。
また、std::wcout
を使うことで、ワイド文字列の出力も可能です。
特に、多言語対応や国際化を進めるアプリケーションでは、これらの技術を適切に使いこなすことが重要です。
最適化と注意点
大量のデータや複雑な文字列操作を行う際には、パフォーマンスの最適化と正しいエンコーディング管理が不可欠です。
ここでは、大規模データ処理時の性能低下を防ぐためのテクニックと、マルチバイト文字列やエンコーディングの混在による落とし穴について解説します。
大規模データ処理時の性能低下回避
reserveによるメモリ確保
std::string
やstd::wstring
の操作において、頻繁な文字列の拡張や再割り当ては処理速度の低下を招きます。
これを防ぐために、事前にreserve()
メソッドを使って必要なメモリ容量を確保しておくことが効果的です。
#include <string>
#include <boost/algorithm/string/replace.hpp>
#include <iostream>
int main() {
std::string largeText;
largeText.reserve(10 * 1024 * 1024); // 10MB分の容量を事前確保
// 大規模な文字列を構築または読み込み
// 例:ファイルからの読み込みや大量のデータの連結
// 置換処理
boost::algorithm::replace_all(largeText, "古い", "新しい");
std::cout << "処理完了" << std::endl;
return 0;
}
このように、reserve()
を使うことで、メモリの再割り当て回数を減らし、処理速度を向上させることができます。
in-place置換とコピー置換の使い分け
置換処理には、文字列を直接変更するin-place
方式と、新たに置換後の文字列を生成するコピー
方式があります。
- in-place置換:
replace_all
やreplace_first
を使い、元の文字列を直接変更します。メモリの再確保が最小限で済み、メモリ効率が良いですが、元のデータを保持したい場合には不適です - コピー置換:
replace_all_copy
やregex_replace
の返り値を新しい文字列に格納します。元のデータを保持しつつ、置換結果を得たい場合に便利です
大量データを扱う場合は、必要に応じてこれらを使い分けることが重要です。
例えば、元のデータを保持したい場合はコピー方式を選び、メモリ効率を重視する場合はin-placeを選択します。
これらの注意点を押さえ、エンコーディングの整合性を保ちながら文字列操作を行うことが、正確で安全な処理の鍵となります。
トラブルシューティング
文字列置換を行う際に直面しやすい問題点とその解決策について解説します。
これらのポイントを押さえることで、予期しない動作やエラーを未然に防ぎ、安定した文字列処理を実現できます。
置換対象がヒットしない場合のチェックポイント
置換対象のパターンが期待通りにヒットしない場合、まず以下の点を確認します。
- パターンの正規表現が正しいか:正規表現の文法ミスやエスケープ漏れがないかを見直します。特に、バックスラッシュや特殊文字のエスケープに注意します
- 対象文字列の内容とエンコーディング:対象文字列が想定通りのエンコーディング(UTF-8、UTF-16など)であるかを確認します。エンコーディングの不一致はヒットしない原因となります
- フラグの設定:
boost::regex
のフラグ設定(例:icase
やnoexcept
)が適切かどうかを見直します。大文字・小文字の区別をしたい場合はicase
を付与します - パターンのマッチング範囲:対象の文字列の一部だけにマッチさせたい場合、正規表現のアンカーや境界指定子
^
や$
が適切かを確認します - デバッグ方法:正規表現のマッチング結果を
boost::regex_match
やboost::regex_search
で検証し、パターンが正しく認識されているかを確認します
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main() {
std::string text = "Sample Text";
boost::regex pattern("未マッチパターン");
if (boost::regex_search(text, pattern)) {
std::cout << "パターンにヒットしました。" << std::endl;
} else {
std::cout << "ヒットしませんでした。" << std::endl;
}
return 0;
}
部分一致による誤置換の防止策
部分一致による誤置換は、意図しない箇所まで置換してしまうことが原因です。
これを防ぐためには、以下の対策を講じます。
- 正規表現の境界指定子を使う:
\\b
(単語境界)や^
、$
を用いて、置換対象の文字列が単語の一部や部分文字列としてだけマッチするようにします
boost::regex pattern("\\bHello\\b");
- 具体的なパターンを設定:曖昧なパターンを避け、できるだけ限定的な正規表現を作成します
- 置換前にマッチ確認:
boost::regex_search
を使って、実際にマッチする箇所を事前に確認し、必要に応じてパターンを調整します - 置換範囲の制御:
regex_replace
のフラグやオプションを利用して、不要な部分まで置換しないように制御します
正規表現エラー発生時の対処法
正規表現のコンパイルやマッチング時にエラーが発生した場合、次の点を確認します。
- 正規表現の文法エラー:エスケープ漏れや括弧の閉じ忘れ、特殊文字の誤用などを見直します。
boost::regex
は例外を投げるため、try-catchブロックで捕捉し、エラーメッセージを取得します
#include <boost/regex.hpp>
#include <iostream>
int main() {
try {
boost::regex pattern("("); // 不正な正規表現
} catch (const boost::regex_error& e) {
std::cerr << "正規表現エラー: " << e.what() << std::endl;
}
return 0;
}
正規表現エラー: Unmatched marking parenthesis ( or \(. The error occurred while parsing the regular expression: '(>>>HERE>>>'.
- フラグの設定ミス:フラグの組み合わせが正しいか、サポートされているフラグかを確認します
- エンコーディングの不一致:Unicode文字列を扱う場合は、正規表現も対応したエンコーディングに合わせて作成します
- ライブラリのバージョン確認:使用しているBoostライブラリのバージョンによって、サポートされる正規表現の仕様やエラー内容が異なる場合があります。最新版を使用し、ドキュメントを確認します
これらのポイントを押さえることで、正規表現のエラーや意図しない動作を未然に防ぎ、安定した文字列置換処理を行うことが可能です。
まとめ
この記事では、Boostライブラリを使った文字列置換の基本から応用までを解説しました。
replace_all
やregex_replace
を用いた方法や、正規表現のキャプチャグループ、複数パターン同時置換の実装例、Unicode対応のポイント、そしてパフォーマンス最適化やトラブル時の対処法も紹介しています。
これらを理解することで、効率的かつ安全に多様な文字列置換処理を行えるようになります。