Annotation of nono/lib/mystring.cpp, revision 1.1.1.6

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.