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

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.9   root       12: #include "ascii_ctype.h"
1.1.1.2   root       13: #include <algorithm>
1.1       root       14: 
                     15: std::string
                     16: string_format(const char *fmt, ...)
                     17: {
                     18:        va_list ap;
                     19:        char *buf;
                     20: 
                     21:        va_start(ap, fmt);
                     22:        vasprintf(&buf, fmt, ap);
                     23:        va_end(ap);
                     24:        std::string rv(buf);
                     25:        free(buf);
                     26: 
                     27:        return rv;
                     28: }
                     29: 
1.1.1.2   root       30: // 文字列 str から先頭の連続する空白文字を取り除いた新しい文字列を返す。
                     31: std::string
                     32: string_ltrim(const std::string& str)
                     33: {
                     34:        auto it = str.begin();
                     35:        for (; it != str.end(); it++) {
1.1.1.9   root       36:                if (!is_ascii_space(*it))
1.1.1.2   root       37:                        break;
                     38:        }
                     39:        return std::string(it, str.end());
                     40: }
                     41: 
                     42: // 文字列 str から末尾の連続する空白文字を取り除く (str を書き換える)。
                     43: void
                     44: string_rtrim(std::string& str)
                     45: {
1.1.1.9   root       46:        while (is_ascii_space(*str.rbegin())) {
1.1.1.2   root       47:                str.pop_back();
                     48:        }
                     49: }
                     50: 
                     51: // 文字列 str から末尾の連続する空白文字を取り除く (str を書き換える)。
                     52: void
                     53: rtrim(char *str)
                     54: {
                     55:        char *p = strchr(str, '\0');
1.1.1.9   root       56:        while (--p >= str && is_ascii_space(*p)) {
1.1.1.2   root       57:                *p = '\0';
                     58:        }
                     59: }
                     60: 
1.1.1.5   root       61: // 文字列 str から先頭と末尾の連続する空白文字を取り除いた新しい文字列を返す。
                     62: std::string
                     63: string_trim(const std::string& str)
                     64: {
                     65:        int s = 0;
                     66:        int e = str.size();
                     67: 
                     68:        for (; s < e; s++) {
1.1.1.9   root       69:                if (!is_ascii_space(str[s]))
1.1.1.5   root       70:                        break;
                     71:        }
                     72:        for (e--; e >= s; e--) {
1.1.1.9   root       73:                if (!is_ascii_space(str[e]))
1.1.1.5   root       74:                        break;
                     75:        }
                     76: 
                     77:        return str.substr(s, e - s + 1);
                     78: }
                     79: 
1.1.1.2   root       80: // 文字列 src 中の ASCII 大文字を小文字にした新しい文字列を返す。
                     81: std::string
                     82: string_tolower(const std::string& src)
                     83: {
                     84:        std::string dst(src);
                     85:        std::transform(dst.begin(), dst.end(), dst.begin(),
                     86:                [](unsigned char c){ return std::tolower(c); });
                     87:        return dst;
                     88: }
                     89: 
1.1.1.7   root       90: // 文字列 src 中の ASCII 小文字を大文字にした新しい文字列を返す。
                     91: std::string
                     92: string_toupper(const std::string& src)
                     93: {
                     94:        std::string dst(src);
                     95:        std::transform(dst.begin(), dst.end(), dst.begin(),
                     96:                [](unsigned char c){ return std::toupper(c); });
                     97:        return dst;
                     98: }
                     99: 
1.1.1.4   root      100: // 文字列 lhs の先頭が rhs と大文字小文字の区別なしで一致すれば true を返す。
                    101: // ASCII 専用。
                    102: // C++20 の starts_with に似せておく。
                    103: bool
                    104: starts_with_ignorecase(const std::string& lhs, const std::string& rhs)
                    105: {
                    106:        if (lhs.length() < rhs.length()) {
                    107:                return false;
                    108:        }
                    109: #if 0
                    110:        return std::equal(
                    111:                lhs.begin(), lhs.begin() + rhs.length(),
                    112:                rhs.begin(),
                    113:                [](std::string::value_type l, std::string::value_type r) {
                    114:                        return std::tolower(l) == std::tolower(r);
                    115:                }
                    116:        );
                    117: #else
                    118:        // こっちのほうが分かりやすいよな
                    119:        return strncasecmp(lhs.c_str(), rhs.c_str(), rhs.length()) == 0;
                    120: #endif
                    121: }
                    122: 
                    123: // 文字列 str (長さ len) を文字 c で分割したリストを返す。
                    124: std::vector<std::string>
1.1.1.5   root      125: string_split(const char *str, int len, char c, int nlimit)
1.1.1.4   root      126: {
                    127:        std::vector<std::string> list;
                    128: 
1.1.1.5   root      129:        // 空文字列なら空リスト
                    130:        if (len == 0) {
                    131:                return list;
                    132:        }
                    133: 
                    134:        int pos = 0;
                    135:        int end = 0;
                    136: 
                    137:        for (; ; pos = end + 1) {
                    138:                // 上限に達するならこれ以降は一要素として返す
                    139:                if (nlimit > 0 && list.size() >= nlimit - 1) {
                    140:                        list.emplace_back(str + pos, len - pos);
                    141:                        break;
                    142:                }
                    143: 
1.1.1.4   root      144:                const char *p = strchr(str + pos, c);
                    145:                if (p) {
                    146:                        end = p - str;
                    147:                } else {
                    148:                        end = len;
                    149:                }
                    150: 
                    151:                list.emplace_back(str + pos, end - pos);
1.1.1.5   root      152:                if (p == NULL)
                    153:                        break;
1.1.1.4   root      154:        }
                    155: 
                    156:        return list;
                    157: }
                    158: 
1.1.1.6   root      159: // val を3桁ずつカンマ区切りした文字列にして返す。最大は 26桁。
                    160: // ex) 123   -> "138"
                    161: //     12345 -> "12,345"
                    162: std::string
                    163: format_number(uint64 val)
                    164: {
                    165:        //                 1   2   3   4   5   6
                    166:        // UINT64_MAX = 18,446,744,073,709,551,615
                    167:        char part[6][8];
                    168:        char buf[32];
                    169:        int n;
                    170: 
                    171:        n = 0;
                    172:        memset(&part, 0, sizeof(part));
                    173:        while (val >= 1000) {
                    174:                uint32 r = val % 1000;
                    175:                val /= 1000;
                    176: 
                    177:                snprintf(part[n], sizeof(part[n]), ",%03u", r);
                    178:                n++;
                    179:        }
                    180:        // この時点で
                    181:        // part[0] = ",615";
                    182:        // part[1] = ",551";
                    183:        // :
                    184:        // part[5] = ",446";
                    185: 
                    186:        // 先頭(val は 1000未満)
                    187:        snprintf(buf, sizeof(buf), "%u", (uint32)val);
                    188: 
                    189:        // part を連結
                    190:        while (--n >= 0) {
                    191:                strlcat(buf, part[n], sizeof(buf));
                    192:        }
                    193:        return std::string(buf);
                    194: }
                    195: 
1.1.1.7   root      196: // value を width 桁の16進数文字列にして返す。"%0{width}x" みたいな感じ。
                    197: // strhex(0x12345678, 4) -> "5678"
                    198: // strhex(0x00000001, 3) -> "001"
                    199: std::string
                    200: strhex(uint32 value, int width)
                    201: {
                    202:        std::string s;
                    203: 
                    204:        for (width -= 1; width >= 0; width--) {
                    205:                uint32 d = (value >> (width * 4)) & 0x0f;
                    206:                if (__predict_true(d < 10)) {
                    207:                        s += '0' + d;
                    208:                } else {
                    209:                        s += 'a' + d - 10;
                    210:                }
                    211:        }
                    212:        return s;
                    213: }
                    214: 
1.1.1.10! root      215: static constexpr bool FORMAT_TSEC = false;
        !           216: static constexpr bool FORMAT_FULL = true;
1.1.1.8   root      217: 
1.1.1.10! root      218: // TimeToStr() と SecToStr() の共通部分。
        !           219: template <bool full_format>
1.1.1.8   root      220: static const std::string
1.1.1.10! root      221: TimeToStrF(uint64 t)
1.1.1.8   root      222: {
                    223:        char buf[32];
                    224:        char *p;
                    225:        size_t len;
                    226:        int n;
                    227: 
                    228:        uint ns = t % 1000;
                    229:        t /= 1000;
                    230:        uint us = t % 1000;
                    231:        t /= 1000;
                    232:        uint ms = t % 1000;
                    233:        t /= 1000;
                    234: 
                    235:        uint s, m, h, d;
1.1.1.10! root      236:        if (full_format) {
1.1.1.8   root      237:                s = t % 60;
                    238:                t /= 60;
                    239:                m = t % 60;
                    240:                t /= 60;
                    241:                h = t % 24;
                    242:                t /= 24;
                    243:                d = t;
                    244:        } else {
                    245:                s = t;
                    246:                m = 0;
                    247:                h = 0;
                    248:                d = 0;
                    249:        }
                    250: 
                    251:        p = buf;
                    252:        len = sizeof(buf);
                    253:        if (d) {
                    254:                n = snprintf(p, len, "%3ud %02u:%02u:%02u", d, h, m, s);
                    255:                p += n;
                    256:                len -= n;
                    257:        } else if (h) {
                    258:                n = snprintf(p, len, "%2u:%02u:%02u", h, m, s);
                    259:                p += n;
                    260:                len -= n;
                    261:        } else if (m) {
                    262:                n = snprintf(p, len, "%2u:%02u", m, s);
                    263:                p += n;
                    264:                len -= n;
                    265:        } else {
                    266:                n = snprintf(p, len, "%u", s);
                    267:                p += n;
                    268:                len -= n;
                    269:        }
                    270:        n = snprintf(p, len, ".%03u'%03u'%03u", ms, us, ns);
                    271:        p += n;
                    272:        len -= n;
                    273: 
                    274:        return std::string(buf, p - buf);
                    275: }
                    276: 
1.1.1.10! root      277: // t [nsec] を文字列に整形して返す。
        !           278: // ex)          1         2
        !           279: //    01234567890123456789012345
        !           280: //   "1.mmm'uuu'nnn"                           10秒未満なら13桁
        !           281: //   "59.mmm'uuu'nnn"                          1分未満なら14桁
        !           282: //   " 9:59.mmm'uuu'nnn"                       1時間未満なら17桁
        !           283: //   " 9:59:59.mmm'uuu'nnn"                    24時間未満なら20桁
        !           284: //   "999d 23:59:59.mmm'uuu'nnn"       1000日未満なら25桁
        !           285: //
        !           286: // 1000日以上になると桁がずれるけど、それはもういいだろう。
        !           287: // 10秒未満の場合だけ %2u ではなく %u で1桁切り詰めているが、これは
        !           288: // FORMAT_TSEC との互換性のため。その必要のない10分未満と10時間未満は
        !           289: // どちらも %2u で表記し桁数を維持することに努める。
1.1.1.8   root      290: const std::string
                    291: TimeToStr(uint64 t)
                    292: {
1.1.1.10! root      293:        return TimeToStrF<FORMAT_FULL>(t);
1.1.1.8   root      294: }
                    295: 
1.1.1.10! root      296: // t [nsec] を文字列にして返す。
        !           297: // 秒以上はすべて %u だけで表す。
        !           298: // 1桁秒以内 (10秒未満) なことが分かっている場合は 13桁。
        !           299: // 2桁秒以上になると伸びていく。前に余白等なし。
        !           300: // ex)
        !           301: //  "1.000'000'000"            (10秒未満なら13桁)
        !           302: //  "10.000'000'000"
        !           303: //  "100.000'000'000"
1.1.1.8   root      304: const std::string
                    305: SecToStr(uint64 t)
                    306: {
1.1.1.10! root      307:        return TimeToStrF<FORMAT_TSEC>(t);
1.1.1.8   root      308: }
                    309: 
1.1.1.7   root      310: 
1.1.1.6   root      311: #if defined(SELFTEST)
1.1       root      312: #include <cstdio>
1.1.1.6   root      313: #include "stopwatch.h"
                    314: std::string s;
1.1       root      315: int main()
                    316: {
1.1.1.6   root      317:        Stopwatch sw;
                    318:        sw.Start();
                    319:        for (uint64 i = 0; i < 10000000; i += 3) {
                    320:                s = format_number(i);
                    321:                if (s.empty())
                    322:                        return 0;
                    323:        }
                    324:        sw.Stop();
1.1.1.10! root      325:        uint64 t = sw.Elapsed_nsec();
        !           326:        printf("%.3f msec\n", (double)t / 1e9);
1.1       root      327:        return 0;
                    328: }
                    329: #endif

unix.superglobalmegacorp.com

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