|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.6 root 7: //
8: // 文字列操作
9: //
10:
1.1 root 11: #include "mystring.h"
1.1.1.2 root 12: #include <algorithm>
1.1 root 13:
14: std::string
15: string_format(const char *fmt, ...)
16: {
17: va_list ap;
18: char *buf;
19:
20: va_start(ap, fmt);
21: vasprintf(&buf, fmt, ap);
22: va_end(ap);
23: std::string rv(buf);
24: free(buf);
25:
26: return rv;
27: }
28:
1.1.1.2 root 29: // 文字列 str から先頭の連続する空白文字を取り除いた新しい文字列を返す。
30: std::string
31: string_ltrim(const std::string& str)
32: {
33: auto it = str.begin();
34: for (; it != str.end(); it++) {
35: if (!isspace(*it))
36: break;
37: }
38: return std::string(it, str.end());
39: }
40:
41: // 文字列 str から末尾の連続する空白文字を取り除く (str を書き換える)。
42: void
43: string_rtrim(std::string& str)
44: {
45: while (isspace(*str.rbegin())) {
46: str.pop_back();
47: }
48: }
49:
50: // 文字列 str から末尾の連続する空白文字を取り除く (str を書き換える)。
51: void
52: rtrim(char *str)
53: {
54: char *p = strchr(str, '\0');
1.1.1.5 root 55: while (--p >= str && isspace((int)*p)) {
1.1.1.2 root 56: *p = '\0';
57: }
58: }
59:
1.1.1.5 root 60: // 文字列 str から先頭と末尾の連続する空白文字を取り除いた新しい文字列を返す。
61: std::string
62: string_trim(const std::string& str)
63: {
64: int s = 0;
65: int e = str.size();
66:
67: for (; s < e; s++) {
68: if (!isspace(str[s]))
69: break;
70: }
71: for (e--; e >= s; e--) {
72: if (!isspace(str[e]))
73: break;
74: }
75:
76: return str.substr(s, e - s + 1);
77: }
78:
1.1.1.2 root 79: // 文字列 src 中の ASCII 大文字を小文字にした新しい文字列を返す。
80: std::string
81: string_tolower(const std::string& src)
82: {
83: std::string dst(src);
84: std::transform(dst.begin(), dst.end(), dst.begin(),
85: [](unsigned char c){ return std::tolower(c); });
86: return dst;
87: }
88:
1.1.1.7 ! root 89: // 文字列 src 中の ASCII 小文字を大文字にした新しい文字列を返す。
! 90: std::string
! 91: string_toupper(const std::string& src)
! 92: {
! 93: std::string dst(src);
! 94: std::transform(dst.begin(), dst.end(), dst.begin(),
! 95: [](unsigned char c){ return std::toupper(c); });
! 96: return dst;
! 97: }
! 98:
1.1.1.4 root 99: // 文字列 lhs の先頭が rhs と大文字小文字の区別なしで一致すれば true を返す。
100: // ASCII 専用。
101: // C++20 の starts_with に似せておく。
102: bool
103: starts_with_ignorecase(const std::string& lhs, const std::string& rhs)
104: {
105: if (lhs.length() < rhs.length()) {
106: return false;
107: }
108: #if 0
109: return std::equal(
110: lhs.begin(), lhs.begin() + rhs.length(),
111: rhs.begin(),
112: [](std::string::value_type l, std::string::value_type r) {
113: return std::tolower(l) == std::tolower(r);
114: }
115: );
116: #else
117: // こっちのほうが分かりやすいよな
118: return strncasecmp(lhs.c_str(), rhs.c_str(), rhs.length()) == 0;
119: #endif
120: }
121:
122: // 文字列 str (長さ len) を文字 c で分割したリストを返す。
123: std::vector<std::string>
1.1.1.5 root 124: string_split(const char *str, int len, char c, int nlimit)
1.1.1.4 root 125: {
126: std::vector<std::string> list;
127:
1.1.1.5 root 128: // 空文字列なら空リスト
129: if (len == 0) {
130: return list;
131: }
132:
133: int pos = 0;
134: int end = 0;
135:
136: for (; ; pos = end + 1) {
137: // 上限に達するならこれ以降は一要素として返す
138: if (nlimit > 0 && list.size() >= nlimit - 1) {
139: list.emplace_back(str + pos, len - pos);
140: break;
141: }
142:
1.1.1.4 root 143: const char *p = strchr(str + pos, c);
144: if (p) {
145: end = p - str;
146: } else {
147: end = len;
148: }
149:
150: list.emplace_back(str + pos, end - pos);
1.1.1.5 root 151: if (p == NULL)
152: break;
1.1.1.4 root 153: }
154:
155: return list;
156: }
157:
1.1.1.6 root 158: // val を3桁ずつカンマ区切りした文字列にして返す。最大は 26桁。
159: // ex) 123 -> "138"
160: // 12345 -> "12,345"
161: std::string
162: format_number(uint64 val)
163: {
164: // 1 2 3 4 5 6
165: // UINT64_MAX = 18,446,744,073,709,551,615
166: char part[6][8];
167: char buf[32];
168: int n;
169:
170: n = 0;
171: memset(&part, 0, sizeof(part));
172: while (val >= 1000) {
173: uint32 r = val % 1000;
174: val /= 1000;
175:
176: snprintf(part[n], sizeof(part[n]), ",%03u", r);
177: n++;
178: }
179: // この時点で
180: // part[0] = ",615";
181: // part[1] = ",551";
182: // :
183: // part[5] = ",446";
184:
185: // 先頭(val は 1000未満)
186: snprintf(buf, sizeof(buf), "%u", (uint32)val);
187:
188: // part を連結
189: while (--n >= 0) {
190: strlcat(buf, part[n], sizeof(buf));
191: }
192: return std::string(buf);
193: }
194:
1.1.1.7 ! root 195: // value を width 桁の16進数文字列にして返す。"%0{width}x" みたいな感じ。
! 196: // strhex(0x12345678, 4) -> "5678"
! 197: // strhex(0x00000001, 3) -> "001"
! 198: std::string
! 199: strhex(uint32 value, int width)
! 200: {
! 201: std::string s;
! 202:
! 203: for (width -= 1; width >= 0; width--) {
! 204: uint32 d = (value >> (width * 4)) & 0x0f;
! 205: if (__predict_true(d < 10)) {
! 206: s += '0' + d;
! 207: } else {
! 208: s += 'a' + d - 10;
! 209: }
! 210: }
! 211: return s;
! 212: }
! 213:
! 214:
1.1.1.6 root 215: #if defined(SELFTEST)
1.1 root 216: #include <cstdio>
1.1.1.6 root 217: #include "stopwatch.h"
218: std::string s;
1.1 root 219: int main()
220: {
1.1.1.6 root 221: Stopwatch sw;
222: sw.Start();
223: for (uint64 i = 0; i < 10000000; i += 3) {
224: s = format_number(i);
225: if (s.empty())
226: return 0;
227: }
228: sw.Stop();
229: uint64 t = sw.Elapsed();
230: printf("%ld.%03ld msec\n", t / 1000 / 1000, (t / 1000) % 1000);
1.1 root 231: return 0;
232: }
233: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.