|
|
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.4 root 89: // 文字列 lhs の先頭が rhs と大文字小文字の区別なしで一致すれば true を返す。
90: // ASCII 専用。
91: // C++20 の starts_with に似せておく。
92: bool
93: starts_with_ignorecase(const std::string& lhs, const std::string& rhs)
94: {
95: if (lhs.length() < rhs.length()) {
96: return false;
97: }
98: #if 0
99: return std::equal(
100: lhs.begin(), lhs.begin() + rhs.length(),
101: rhs.begin(),
102: [](std::string::value_type l, std::string::value_type r) {
103: return std::tolower(l) == std::tolower(r);
104: }
105: );
106: #else
107: // こっちのほうが分かりやすいよな
108: return strncasecmp(lhs.c_str(), rhs.c_str(), rhs.length()) == 0;
109: #endif
110: }
111:
112: // 文字列 str (長さ len) を文字 c で分割したリストを返す。
113: std::vector<std::string>
1.1.1.5 root 114: string_split(const char *str, int len, char c, int nlimit)
1.1.1.4 root 115: {
116: std::vector<std::string> list;
117:
1.1.1.5 root 118: // 空文字列なら空リスト
119: if (len == 0) {
120: return list;
121: }
122:
123: int pos = 0;
124: int end = 0;
125:
126: for (; ; pos = end + 1) {
127: // 上限に達するならこれ以降は一要素として返す
128: if (nlimit > 0 && list.size() >= nlimit - 1) {
129: list.emplace_back(str + pos, len - pos);
130: break;
131: }
132:
1.1.1.4 root 133: const char *p = strchr(str + pos, c);
134: if (p) {
135: end = p - str;
136: } else {
137: end = len;
138: }
139:
140: list.emplace_back(str + pos, end - pos);
1.1.1.5 root 141: if (p == NULL)
142: break;
1.1.1.4 root 143: }
144:
145: return list;
146: }
147:
1.1.1.6 ! root 148: // val を3桁ずつカンマ区切りした文字列にして返す。最大は 26桁。
! 149: // ex) 123 -> "138"
! 150: // 12345 -> "12,345"
! 151: std::string
! 152: format_number(uint64 val)
! 153: {
! 154: // 1 2 3 4 5 6
! 155: // UINT64_MAX = 18,446,744,073,709,551,615
! 156: char part[6][8];
! 157: char buf[32];
! 158: int n;
! 159:
! 160: n = 0;
! 161: memset(&part, 0, sizeof(part));
! 162: while (val >= 1000) {
! 163: uint32 r = val % 1000;
! 164: val /= 1000;
! 165:
! 166: snprintf(part[n], sizeof(part[n]), ",%03u", r);
! 167: n++;
! 168: }
! 169: // この時点で
! 170: // part[0] = ",615";
! 171: // part[1] = ",551";
! 172: // :
! 173: // part[5] = ",446";
! 174:
! 175: // 先頭(val は 1000未満)
! 176: snprintf(buf, sizeof(buf), "%u", (uint32)val);
! 177:
! 178: // part を連結
! 179: while (--n >= 0) {
! 180: strlcat(buf, part[n], sizeof(buf));
! 181: }
! 182: return std::string(buf);
! 183: }
! 184:
! 185: #if defined(SELFTEST)
1.1 root 186: #include <cstdio>
1.1.1.6 ! root 187: #include "stopwatch.h"
! 188: std::string s;
1.1 root 189: int main()
190: {
1.1.1.6 ! root 191: Stopwatch sw;
! 192: sw.Start();
! 193: for (uint64 i = 0; i < 10000000; i += 3) {
! 194: s = format_number(i);
! 195: if (s.empty())
! 196: return 0;
! 197: }
! 198: sw.Stop();
! 199: uint64 t = sw.Elapsed();
! 200: printf("%ld.%03ld msec\n", t / 1000 / 1000, (t / 1000) % 1000);
1.1 root 201: return 0;
202: }
203: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.