--- nono/lib/mystring.cpp 2026/04/29 17:04:54 1.1.1.4 +++ nono/lib/mystring.cpp 2026/04/29 17:05:08 1.1.1.6 @@ -4,6 +4,10 @@ // Licensed under nono-license.txt // +// +// 文字列操作 +// + #include "mystring.h" #include @@ -48,11 +52,30 @@ void rtrim(char *str) { char *p = strchr(str, '\0'); - while (--p >= str && (isspace((int)*p) || *p == '\r' || *p == '\n')) { + while (--p >= str && isspace((int)*p)) { *p = '\0'; } } +// 文字列 str から先頭と末尾の連続する空白文字を取り除いた新しい文字列を返す。 +std::string +string_trim(const std::string& str) +{ + int s = 0; + int e = str.size(); + + for (; s < e; s++) { + if (!isspace(str[s])) + break; + } + for (e--; e >= s; e--) { + if (!isspace(str[e])) + break; + } + + return str.substr(s, e - s + 1); +} + // 文字列 src 中の ASCII 大文字を小文字にした新しい文字列を返す。 std::string string_tolower(const std::string& src) @@ -88,11 +111,25 @@ starts_with_ignorecase(const std::string // 文字列 str (長さ len) を文字 c で分割したリストを返す。 std::vector -string_split(const char *str, int len, char c) +string_split(const char *str, int len, char c, int nlimit) { std::vector list; - for (int pos = 0, end = 0 ; pos < len; pos = end + 1) { + // 空文字列なら空リスト + if (len == 0) { + return list; + } + + int pos = 0; + int end = 0; + + for (; ; pos = end + 1) { + // 上限に達するならこれ以降は一要素として返す + if (nlimit > 0 && list.size() >= nlimit - 1) { + list.emplace_back(str + pos, len - pos); + break; + } + const char *p = strchr(str + pos, c); if (p) { end = p - str; @@ -101,30 +138,66 @@ string_split(const char *str, int len, c } list.emplace_back(str + pos, end - pos); + if (p == NULL) + break; } return list; } -#if 0 +// val を3桁ずつカンマ区切りした文字列にして返す。最大は 26桁。 +// ex) 123 -> "138" +// 12345 -> "12,345" +std::string +format_number(uint64 val) +{ + // 1 2 3 4 5 6 + // UINT64_MAX = 18,446,744,073,709,551,615 + char part[6][8]; + char buf[32]; + int n; + + n = 0; + memset(&part, 0, sizeof(part)); + while (val >= 1000) { + uint32 r = val % 1000; + val /= 1000; + + snprintf(part[n], sizeof(part[n]), ",%03u", r); + n++; + } + // この時点で + // part[0] = ",615"; + // part[1] = ",551"; + // : + // part[5] = ",446"; + + // 先頭(val は 1000未満) + snprintf(buf, sizeof(buf), "%u", (uint32)val); + + // part を連結 + while (--n >= 0) { + strlcat(buf, part[n], sizeof(buf)); + } + return std::string(buf); +} + +#if defined(SELFTEST) #include -#include +#include "stopwatch.h" +std::string s; int main() { - std::string s0 = string_format("%d_%d", 0, 1); - if (s0 != "0_1") { - printf("error\n"); - return 1; - } - timeval start, end, result; - gettimeofday(&start, NULL); - for (int i = 0; i < 100000; i++) { - std::string s = string_format("%d_%d", i, i); - } - gettimeofday(&end, NULL); - timersub(&end, &start, &result); - long long t = (result.tv_sec) * 1000000 + result.tv_usec; - printf("%d.%03d\n", (int)t / 1000, (int)t % 1000); + Stopwatch sw; + sw.Start(); + for (uint64 i = 0; i < 10000000; i += 3) { + s = format_number(i); + if (s.empty()) + return 0; + } + sw.Stop(); + uint64 t = sw.Elapsed(); + printf("%ld.%03ld msec\n", t / 1000 / 1000, (t / 1000) % 1000); return 0; } #endif