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

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.8   root      215: #define FORMAT_FULL 0
                    216: #define FORMAT_SEC 1
                    217: 
                    218: // 経過時間 t を文字列にして返す。
                    219: // 文字列長は、t の大きさ(とフォーマット指定)によって以下の通り。
                    220: //
                    221: //  0         1         2
                    222: //  01234567890123456789012345
                    223: // "0.mmm'uuu'nnn"              10秒未満、または FORMAT_SEC なら13桁
                    224: // "59.mmm'uuu'nnn"             1分未満なら14桁
                    225: // " 9:59.mmm'uuu'nnn"          1時間未満なら17桁
                    226: // " 9:59:59.mmm'uuu'nnn"       24時間未満なら20桁
                    227: // "999d 23:59:59.mmm'uuu'nnn"  1日以上なら25桁。これが最大幅。
                    228: //
                    229: // FORMAT_SEC は1桁秒以下の場合 (実際には1秒未満の場合) に用いる。
                    230: // FORMAT_FULL は 1000日経過すると桁がずれるけど、それはもういいだろう。
                    231: //
                    232: // 10秒未満の場合だけ %2u ではなく %u で1桁切り詰めているが、これは
                    233: // FORMAT_SEC との互換性のため。その必要のない10分未満と10時間未満は
                    234: // どちらも %2u で表記し桁数を維持することに努める。
                    235: static const std::string
                    236: TimeToStrF(uint64 t, int format)
                    237: {
                    238:        char buf[32];
                    239:        char *p;
                    240:        size_t len;
                    241:        int n;
                    242: 
                    243:        uint ns = t % 1000;
                    244:        t /= 1000;
                    245:        uint us = t % 1000;
                    246:        t /= 1000;
                    247:        uint ms = t % 1000;
                    248:        t /= 1000;
                    249: 
                    250:        uint s, m, h, d;
                    251:        if (format == FORMAT_FULL) {
                    252:                s = t % 60;
                    253:                t /= 60;
                    254:                m = t % 60;
                    255:                t /= 60;
                    256:                h = t % 24;
                    257:                t /= 24;
                    258:                d = t;
                    259:        } else {
                    260:                s = t;
                    261:                m = 0;
                    262:                h = 0;
                    263:                d = 0;
                    264:        }
                    265: 
                    266:        p = buf;
                    267:        len = sizeof(buf);
                    268:        if (d) {
                    269:                n = snprintf(p, len, "%3ud %02u:%02u:%02u", d, h, m, s);
                    270:                p += n;
                    271:                len -= n;
                    272:        } else if (h) {
                    273:                n = snprintf(p, len, "%2u:%02u:%02u", h, m, s);
                    274:                p += n;
                    275:                len -= n;
                    276:        } else if (m) {
                    277:                n = snprintf(p, len, "%2u:%02u", m, s);
                    278:                p += n;
                    279:                len -= n;
                    280:        } else {
                    281:                n = snprintf(p, len, "%u", s);
                    282:                p += n;
                    283:                len -= n;
                    284:        }
                    285:        n = snprintf(p, len, ".%03u'%03u'%03u", ms, us, ns);
                    286:        p += n;
                    287:        len -= n;
                    288: 
                    289:        return std::string(buf, p - buf);
                    290: }
                    291: 
                    292: const std::string
                    293: TimeToStr(uint64 t)
                    294: {
                    295:        return TimeToStrF(t, FORMAT_FULL);
                    296: }
                    297: 
                    298: const std::string
                    299: SecToStr(uint64 t)
                    300: {
                    301:        return TimeToStrF(t, FORMAT_SEC);
                    302: }
                    303: 
1.1.1.7   root      304: 
1.1.1.6   root      305: #if defined(SELFTEST)
1.1       root      306: #include <cstdio>
1.1.1.6   root      307: #include "stopwatch.h"
                    308: std::string s;
1.1       root      309: int main()
                    310: {
1.1.1.6   root      311:        Stopwatch sw;
                    312:        sw.Start();
                    313:        for (uint64 i = 0; i < 10000000; i += 3) {
                    314:                s = format_number(i);
                    315:                if (s.empty())
                    316:                        return 0;
                    317:        }
                    318:        sw.Stop();
                    319:        uint64 t = sw.Elapsed();
                    320:        printf("%ld.%03ld msec\n", t / 1000 / 1000, (t / 1000) % 1000);
1.1       root      321:        return 0;
                    322: }
                    323: #endif

unix.superglobalmegacorp.com

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