tools
読み取り中…
検索中…
一致する文字列を見つけられません
string.h
[詳解]
1#pragma once
2#include <string>
3#include <vector>
4#include <sstream>
5#include <unordered_map>
6#include <algorithm>
7#ifdef UNICODE
8 #include <boost/locale.hpp>
9#endif
10
11/**
12 * @file string.h
13 * @brief 文字列操作ユーティリティ
14 *
15 * 文字列の置換・検索・分割・変換など、よく使う文字列操作関数を
16 * `st` 名前空間および汎用関数として提供します。
17 * UNICODE ビルド時は Boost.Locale による UTF-8/wstring 変換も利用できます。
18 */
19
20/**
21 * @brief 文字列が複数の候補値のいずれかと等しいか判定する
22 * @tparam Args 可変テンプレート引数(std::string に変換可能な型)
23 * @param value 判定する文字列
24 * @param args 比較する候補値(可変長)
25 * @return value が args のいずれかと等しい場合 true
26 *
27 * @code
28 * if (is_or(cmd, "quit", "exit", "q")) return;
29 * @endcode
30 */
31template <typename... Args> inline bool is_or(const std::string& value, Args... args) {
32 std::vector<std::string> values = {args...};
33 return std::find(values.begin(), values.end(), value) != values.end();
34}
35
36/**
37 * @namespace st
38 * @brief 文字列ユーティリティ用名前空間
39 */
40namespace st {
41
42#ifdef UNICODE
43 /**
44 * @brief UTF-8 文字列を wstring に変換する(UNICODE ビルド専用)
45 * @param u8 変換元の UTF-8 文字列
46 * @return 変換後の wstring
47 */
48 inline std::wstring to_wstring(const std::string& u8) {
49 return boost::locale::conv::to_utf<wchar_t>(u8, "UTF-8");
50 }
51#endif
52
53/**
54 * @brief 文字列中のすべての from を to に置換する(参照渡し、インプレース版)
55 * @param str 置換対象の文字列(この文字列が変更される)
56 * @param from 置換前の文字列
57 * @param to 置換後の文字列
58 * @note from が空文字列の場合は何もしません
59 */
60inline void replace_r(std::string& str, const std::string from, const std::string to) {
61 if (from.empty()) return; // 空文字列を弾く
62 size_t start_pos = 0;
63 while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
64 str.replace(start_pos, from.size(), to);
65 start_pos += to.size();
66 }
67}
68
69/**
70 * @brief 文字列中のすべての from を to に置換した新しい文字列を返す(値返し版)
71 * @param str 置換元の文字列(変更されない)
72 * @param from 置換前の文字列
73 * @param to 置換後の文字列
74 * @return 置換後の文字列
75 */
76inline std::string replace(std::string str, const std::string from, const std::string to) {
77 replace_r(str,from,to);
78 return str;
79}
80
81/**
82 * @brief 文字列中から start〜end に囲まれた部分文字列をすべて取り出す
83 * @param input 検索対象の文字列
84 * @param start 開始デリミタ
85 * @param end 終了デリミタ
86 * @return 開始デリミタと終了デリミタの間の部分文字列のベクタ
87 */
88inline std::vector<std::string> find(const std::string& input, std::string start, std::string end) {
89 std::vector<std::string> output;
90 int startpos = 0;
91 while(true) {
92 // 検索
93 size_t f = input.find(start,startpos);
94 size_t b = input.find(end, f);
95 if (f==std::string::npos || b==std::string::npos) break;
96 // 部分文字列を抽出
97 output.emplace_back(input.substr(f + start.size(), b - f - start.size()));
98 startpos = b+1;
99 }
100 return output;
101}
102
103/**
104 * @brief 文字列中の数字のみを抽出して整数に変換する
105 * @param str 変換元の文字列
106 * @return 数字部分のみを連結して変換した整数値。数字がない場合は 0
107 */
108inline int toi(const std::string& str) {
109 std::string filtered;
110 std::copy_if(str.begin(), str.end(), std::back_inserter(filtered),
111 [](unsigned char c) { return std::isdigit(c); });
112
113 return filtered.empty() ? 0 : std::stoi(filtered);
114}
115
116/**
117 * @brief 文字列ベクタの各要素を toi で整数に変換する
118 * @param input 変換元の文字列ベクタ
119 * @return 変換後の整数ベクタ
120 */
121inline std::vector<int> toi(const std::vector<std::string>& input) {
122 std::vector<int> result;
123 for (std::string e: input) {
124 result.emplace_back(st::toi(e));
125 }
126 return result;
127}
128
129/**
130 * @brief 文字列を単一のデリミタで分割する(文字列ベクタを返す)
131 * @param str 分割する文字列
132 * @param delimiter デリミタ文字列
133 * @return 分割結果の文字列ベクタ
134 */
135inline std::vector<std::string> split(const std::string& str, const std::string& delimiter) {
136 std::vector<std::string> tokens;
137 size_t start = 0, end;
138
139 while ((end = str.find(delimiter, start)) != std::string::npos) {
140 tokens.emplace_back(str.substr(start, end - start));
141 start = end + delimiter.size();
142 }
143 tokens.emplace_back(str.substr(start));
144 return tokens;
145}
146
147/**
148 * @brief 文字列を単一のデリミタで分割し、各要素を整数に変換する
149 * @param str 分割する文字列
150 * @param delimiter デリミタ文字列
151 * @return 分割・変換後の整数ベクタ
152 */
153inline std::vector<int> spliti(const std::string& str, const std::string& delimiter) {
154 std::vector<std::string> output = split(str,delimiter);
155 std::vector<int> result;
156 for (std::string e: output) {
157 result.emplace_back(st::toi(e));
158 }
159 return result;
160}
161
162/// @brief split() の複数デリミタ対応版の戻り値型: デリミタ → 部分文字列リスト
163typedef std::unordered_map<std::string,std::vector<std::string>> splits;
164/// @brief spliti() の複数デリミタ対応版の戻り値型: デリミタ → 整数リスト
165typedef std::unordered_map<std::string,std::vector<int>> splitsi;
166
167/**
168 * @brief 文字列を複数のデリミタで分割し、どのデリミタで区切られたかを記録する
169 * @param input 分割する文字列
170 * @param targets 検索するデリミタ文字列のベクタ
171 * @return デリミタをキー、そのデリミタで終わる部分文字列リストを値とするマップ
172 */
173inline splits split(const std::string& input, const std::vector<std::string>& targets) {
174 splits result;
175 std::string current = input;
176 std::string current_segment;
177 std::string current_delimiter;
178
179 auto find_next_target = [&](const std::string& str, size_t start_pos) {
180 size_t min_pos = std::string::npos;
181 std::string found_target;
182 for (const auto& target : targets) {
183 size_t pos = str.find(target, start_pos);
184 if (pos != std::string::npos && (min_pos == std::string::npos || pos < min_pos)) {
185 min_pos = pos;
186 found_target = target;
187 }
188 }
189 return std::make_pair(min_pos, found_target);
190 };
191
192 size_t pos = 0;
193 while (pos < current.size()) {
194 auto [next_pos, delimiter] = find_next_target(current, pos);
195 if (next_pos == std::string::npos) break;
196 current_segment = current.substr(pos, next_pos - pos + delimiter.size());
197 current_delimiter = delimiter;
198
199 result[current_delimiter].push_back(current_segment);
200
201 pos = next_pos + delimiter.size();
202 }
203
204 return result;
205}
206
207/**
208 * @brief 複数デリミタ版 split の結果を整数に変換する
209 * @param input 分割する文字列
210 * @param targets 検索するデリミタ文字列のベクタ
211 * @return デリミタをキー、整数リストを値とするマップ
212 */
213inline splitsi spliti(const std::string& input, const std::vector<std::string>& targets) {
214 splitsi result;
215 splits output = split(input,targets);
216 for (const auto& [key, segments] : output) {
217 for (const auto& segment : segments) {
218 result[key].push_back(st::toi(segment));
219 }
220 }
221 return result;
222}
223
224/**
225 * @brief char 配列 (argc/argv 形式) を文字列ベクタに変換する
226 * @param i_argc 引数の数
227 * @param i_argv 引数文字列の配列
228 * @return 文字列ベクタ
229 */
230inline std::vector<std::string> charV(const int i_argc, const char* const i_argv[]) {
231 std::vector<std::string> result;
232 for (int i = 0; i < i_argc; ++i) {
233 result.emplace_back(i_argv[i]);
234 }
235 return result;
236}
237
238/**
239 * @brief char 配列 (argc/argv 形式) を整数ベクタに変換する
240 * @param i_argc 引数の数
241 * @param i_argv 引数文字列の配列
242 * @return 数字を抽出した整数ベクタ
243 */
244inline std::vector<int> charVi(const int i_argc, const char* i_argv[]) {
245 return st::toi(st::charV(i_argc,i_argv));
246}
247
248/**
249 * @brief UTF-8 文字列のマルチバイト文字数(文字単位の長さ)を返す
250 * @param input UTF-8 エンコードされた文字列
251 * @return 文字列の文字数(バイト数ではなく文字数)
252 * @note ASCII (1バイト), 2バイト文字, 3バイト文字(日本語など), 4バイト文字に対応
253 */
254inline size_t size(const std::string& input) {
255 unsigned char lead;
256 size_t char_size=0, input_size=0, pos;
257 for (pos = 0; pos < input.size(); pos += char_size) {
258 input_size++;
259 lead = input[pos];
260 if (lead < 0x80) char_size=1; else if (lead < 0xE0) char_size=2; else if (lead < 0xF0) char_size=3; else char_size=4;
261 }
262 return input_size;
263}
264
265}
文字列ユーティリティ用名前空間
size_t size(const std::string &input)
UTF-8 文字列のマルチバイト文字数(文字単位の長さ)を返す
Definition string.h:254
std::vector< std::string > find(const std::string &input, std::string start, std::string end)
文字列中から start〜end に囲まれた部分文字列をすべて取り出す
Definition string.h:88
std::unordered_map< std::string, std::vector< std::string > > splits
split() の複数デリミタ対応版の戻り値型: デリミタ → 部分文字列リスト
Definition string.h:163
std::vector< int > charVi(const int i_argc, const char *i_argv[])
char 配列 (argc/argv 形式) を整数ベクタに変換する
Definition string.h:244
std::vector< int > spliti(const std::string &str, const std::string &delimiter)
文字列を単一のデリミタで分割し、各要素を整数に変換する
Definition string.h:153
std::vector< std::string > charV(const int i_argc, const char *const i_argv[])
char 配列 (argc/argv 形式) を文字列ベクタに変換する
Definition string.h:230
std::string replace(std::string str, const std::string from, const std::string to)
文字列中のすべての from を to に置換した新しい文字列を返す(値返し版)
Definition string.h:76
void replace_r(std::string &str, const std::string from, const std::string to)
文字列中のすべての from を to に置換する(参照渡し、インプレース版)
Definition string.h:60
std::vector< std::string > split(const std::string &str, const std::string &delimiter)
文字列を単一のデリミタで分割する(文字列ベクタを返す)
Definition string.h:135
int toi(const std::string &str)
文字列中の数字のみを抽出して整数に変換する
Definition string.h:108
std::unordered_map< std::string, std::vector< int > > splitsi
spliti() の複数デリミタ対応版の戻り値型: デリミタ → 整数リスト
Definition string.h:165
bool is_or(const std::string &value, Args... args)
文字列が複数の候補値のいずれかと等しいか判定する
Definition string.h:31
@ c
マイクロ秒
Definition time.h:26