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

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.7   root       89: // 文字列 src 中の ASCII 小文字を大文字にした新しい文字列を返す。
                     90: std::string
                     91: string_toupper(const std::string& src)
                     92: {
                     93:        std::string dst(src);
                     94:        std::transform(dst.begin(), dst.end(), dst.begin(),
                     95:                [](unsigned char c){ return std::toupper(c); });
                     96:        return dst;
                     97: }
                     98: 
1.1.1.4   root       99: // 文字列 lhs の先頭が rhs と大文字小文字の区別なしで一致すれば true を返す。
                    100: // ASCII 専用。
                    101: // C++20 の starts_with に似せておく。
                    102: bool
                    103: starts_with_ignorecase(const std::string& lhs, const std::string& rhs)
                    104: {
                    105:        if (lhs.length() < rhs.length()) {
                    106:                return false;
                    107:        }
                    108: #if 0
                    109:        return std::equal(
                    110:                lhs.begin(), lhs.begin() + rhs.length(),
                    111:                rhs.begin(),
                    112:                [](std::string::value_type l, std::string::value_type r) {
                    113:                        return std::tolower(l) == std::tolower(r);
                    114:                }
                    115:        );
                    116: #else
                    117:        // こっちのほうが分かりやすいよな
                    118:        return strncasecmp(lhs.c_str(), rhs.c_str(), rhs.length()) == 0;
                    119: #endif
                    120: }
                    121: 
                    122: // 文字列 str (長さ len) を文字 c で分割したリストを返す。
                    123: std::vector<std::string>
1.1.1.5   root      124: string_split(const char *str, int len, char c, int nlimit)
1.1.1.4   root      125: {
                    126:        std::vector<std::string> list;
                    127: 
1.1.1.5   root      128:        // 空文字列なら空リスト
                    129:        if (len == 0) {
                    130:                return list;
                    131:        }
                    132: 
                    133:        int pos = 0;
                    134:        int end = 0;
                    135: 
                    136:        for (; ; pos = end + 1) {
                    137:                // 上限に達するならこれ以降は一要素として返す
                    138:                if (nlimit > 0 && list.size() >= nlimit - 1) {
                    139:                        list.emplace_back(str + pos, len - pos);
                    140:                        break;
                    141:                }
                    142: 
1.1.1.4   root      143:                const char *p = strchr(str + pos, c);
                    144:                if (p) {
                    145:                        end = p - str;
                    146:                } else {
                    147:                        end = len;
                    148:                }
                    149: 
                    150:                list.emplace_back(str + pos, end - pos);
1.1.1.5   root      151:                if (p == NULL)
                    152:                        break;
1.1.1.4   root      153:        }
                    154: 
                    155:        return list;
                    156: }
                    157: 
1.1.1.6   root      158: // val を3桁ずつカンマ区切りした文字列にして返す。最大は 26桁。
                    159: // ex) 123   -> "138"
                    160: //     12345 -> "12,345"
                    161: std::string
                    162: format_number(uint64 val)
                    163: {
                    164:        //                 1   2   3   4   5   6
                    165:        // UINT64_MAX = 18,446,744,073,709,551,615
                    166:        char part[6][8];
                    167:        char buf[32];
                    168:        int n;
                    169: 
                    170:        n = 0;
                    171:        memset(&part, 0, sizeof(part));
                    172:        while (val >= 1000) {
                    173:                uint32 r = val % 1000;
                    174:                val /= 1000;
                    175: 
                    176:                snprintf(part[n], sizeof(part[n]), ",%03u", r);
                    177:                n++;
                    178:        }
                    179:        // この時点で
                    180:        // part[0] = ",615";
                    181:        // part[1] = ",551";
                    182:        // :
                    183:        // part[5] = ",446";
                    184: 
                    185:        // 先頭(val は 1000未満)
                    186:        snprintf(buf, sizeof(buf), "%u", (uint32)val);
                    187: 
                    188:        // part を連結
                    189:        while (--n >= 0) {
                    190:                strlcat(buf, part[n], sizeof(buf));
                    191:        }
                    192:        return std::string(buf);
                    193: }
                    194: 
1.1.1.7   root      195: // value を width 桁の16進数文字列にして返す。"%0{width}x" みたいな感じ。
                    196: // strhex(0x12345678, 4) -> "5678"
                    197: // strhex(0x00000001, 3) -> "001"
                    198: std::string
                    199: strhex(uint32 value, int width)
                    200: {
                    201:        std::string s;
                    202: 
                    203:        for (width -= 1; width >= 0; width--) {
                    204:                uint32 d = (value >> (width * 4)) & 0x0f;
                    205:                if (__predict_true(d < 10)) {
                    206:                        s += '0' + d;
                    207:                } else {
                    208:                        s += 'a' + d - 10;
                    209:                }
                    210:        }
                    211:        return s;
                    212: }
                    213: 
1.1.1.8 ! root      214: #define FORMAT_FULL 0
        !           215: #define FORMAT_SEC 1
        !           216: 
        !           217: // 経過時間 t を文字列にして返す。
        !           218: // 文字列長は、t の大きさ(とフォーマット指定)によって以下の通り。
        !           219: //
        !           220: //  0         1         2
        !           221: //  01234567890123456789012345
        !           222: // "0.mmm'uuu'nnn"              10秒未満、または FORMAT_SEC なら13桁
        !           223: // "59.mmm'uuu'nnn"             1分未満なら14桁
        !           224: // " 9:59.mmm'uuu'nnn"          1時間未満なら17桁
        !           225: // " 9:59:59.mmm'uuu'nnn"       24時間未満なら20桁
        !           226: // "999d 23:59:59.mmm'uuu'nnn"  1日以上なら25桁。これが最大幅。
        !           227: //
        !           228: // FORMAT_SEC は1桁秒以下の場合 (実際には1秒未満の場合) に用いる。
        !           229: // FORMAT_FULL は 1000日経過すると桁がずれるけど、それはもういいだろう。
        !           230: //
        !           231: // 10秒未満の場合だけ %2u ではなく %u で1桁切り詰めているが、これは
        !           232: // FORMAT_SEC との互換性のため。その必要のない10分未満と10時間未満は
        !           233: // どちらも %2u で表記し桁数を維持することに努める。
        !           234: static const std::string
        !           235: TimeToStrF(uint64 t, int format)
        !           236: {
        !           237:        char buf[32];
        !           238:        char *p;
        !           239:        size_t len;
        !           240:        int n;
        !           241: 
        !           242:        uint ns = t % 1000;
        !           243:        t /= 1000;
        !           244:        uint us = t % 1000;
        !           245:        t /= 1000;
        !           246:        uint ms = t % 1000;
        !           247:        t /= 1000;
        !           248: 
        !           249:        uint s, m, h, d;
        !           250:        if (format == FORMAT_FULL) {
        !           251:                s = t % 60;
        !           252:                t /= 60;
        !           253:                m = t % 60;
        !           254:                t /= 60;
        !           255:                h = t % 24;
        !           256:                t /= 24;
        !           257:                d = t;
        !           258:        } else {
        !           259:                s = t;
        !           260:                m = 0;
        !           261:                h = 0;
        !           262:                d = 0;
        !           263:        }
        !           264: 
        !           265:        p = buf;
        !           266:        len = sizeof(buf);
        !           267:        if (d) {
        !           268:                n = snprintf(p, len, "%3ud %02u:%02u:%02u", d, h, m, s);
        !           269:                p += n;
        !           270:                len -= n;
        !           271:        } else if (h) {
        !           272:                n = snprintf(p, len, "%2u:%02u:%02u", h, m, s);
        !           273:                p += n;
        !           274:                len -= n;
        !           275:        } else if (m) {
        !           276:                n = snprintf(p, len, "%2u:%02u", m, s);
        !           277:                p += n;
        !           278:                len -= n;
        !           279:        } else {
        !           280:                n = snprintf(p, len, "%u", s);
        !           281:                p += n;
        !           282:                len -= n;
        !           283:        }
        !           284:        n = snprintf(p, len, ".%03u'%03u'%03u", ms, us, ns);
        !           285:        p += n;
        !           286:        len -= n;
        !           287: 
        !           288:        return std::string(buf, p - buf);
        !           289: }
        !           290: 
        !           291: const std::string
        !           292: TimeToStr(uint64 t)
        !           293: {
        !           294:        return TimeToStrF(t, FORMAT_FULL);
        !           295: }
        !           296: 
        !           297: const std::string
        !           298: SecToStr(uint64 t)
        !           299: {
        !           300:        return TimeToStrF(t, FORMAT_SEC);
        !           301: }
        !           302: 
1.1.1.7   root      303: 
1.1.1.6   root      304: #if defined(SELFTEST)
1.1       root      305: #include <cstdio>
1.1.1.6   root      306: #include "stopwatch.h"
                    307: std::string s;
1.1       root      308: int main()
                    309: {
1.1.1.6   root      310:        Stopwatch sw;
                    311:        sw.Start();
                    312:        for (uint64 i = 0; i < 10000000; i += 3) {
                    313:                s = format_number(i);
                    314:                if (s.empty())
                    315:                        return 0;
                    316:        }
                    317:        sw.Stop();
                    318:        uint64 t = sw.Elapsed();
                    319:        printf("%ld.%03ld msec\n", t / 1000 / 1000, (t / 1000) % 1000);
1.1       root      320:        return 0;
                    321: }
                    322: #endif

unix.superglobalmegacorp.com

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