From: Nicolas Williams Date: Fri, 29 Nov 2013 04:27:23 +0000 (-0600) Subject: Add string division by string (split on separator) X-Git-Tag: jq-1.4~76^2~24 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cf562961b7fa35e13fbe8a4ac9a6d7836a0ecde9;p=jq Add string division by string (split on separator) --- diff --git a/builtin.c b/builtin.c index 1e38482..0768226 100644 --- a/builtin.c +++ b/builtin.c @@ -160,6 +160,8 @@ static jv f_divide(jv input, jv a, jv b) { jv_free(input); if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { return jv_number(jv_number_value(a) / jv_number_value(b)); + } else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) { + return jv_string_split(a, b); } else { return type_error2(a, b, "cannot be divided"); } @@ -539,6 +541,7 @@ static const struct cfunction function_list[] = { {(cfunction_ptr)f_keys, "keys", 1}, {(cfunction_ptr)f_startswith, "startswith", 2}, {(cfunction_ptr)f_endswith, "endswith", 2}, + {(cfunction_ptr)jv_string_split, "split", 2}, {(cfunction_ptr)jv_string_explode, "explode", 1}, {(cfunction_ptr)jv_string_implode, "implode", 1}, {(cfunction_ptr)jv_setpath, "setpath", 3}, // FIXME typechecking diff --git a/jv.c b/jv.c index d9a908c..671f8d2 100644 --- a/jv.c +++ b/jv.c @@ -596,6 +596,54 @@ int jv_string_length_codepoints(jv j) { return len; } +#ifndef HAVE_MEMMEM +static const void *memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + const char *h = haystack; + const char *n = needle; + size_t hi, hi2, ni; + + if (haystacklen < needlelen || haystacklen == 0) + return NULL; + for (hi = 0; hi < (haystacklen - needlelen + 1); hi++) { + for (ni = 0, hi2 = hi; ni < needlelen; ni++, hi2++) { + if (h[hi2] != n[ni]) + goto not_this; + } + + return &h[hi]; + +not_this: + continue; + } + return NULL; +} +#endif /* HAVE_MEMMEM */ + +jv jv_string_split(jv j, jv sep) { + assert(jv_get_kind(j) == JV_KIND_STRING); + assert(jv_get_kind(sep) == JV_KIND_STRING); + const char *jstr = jv_string_value(j); + const char *sepstr = jv_string_value(sep); + const char *p, *s; + int jlen = jv_string_length_bytes(jv_copy(j)); + int seplen = jv_string_length_bytes(jv_copy(sep)); + jv a = jv_array(); + + assert(jv_get_refcnt(a) == 1); + + for (p = jstr; p < jstr + jlen; p = s + seplen) { + s = memmem(p, (jstr + jlen) - p, sepstr, seplen); + if (s == NULL) + s = jstr + jlen; + a = jv_array_append(a, jv_string_sized(p, s - p)); + } + jv_free(j); + jv_free(sep); + return a; +} + jv jv_string_explode(jv j) { assert(jv_get_kind(j) == JV_KIND_STRING); const char* i = jv_string_value(j); diff --git a/jv.h b/jv.h index a0bc3d4..921345c 100644 --- a/jv.h +++ b/jv.h @@ -87,6 +87,7 @@ jv jv_string_fmt(const char*, ...); jv jv_string_append_codepoint(jv a, uint32_t c); jv jv_string_append_buf(jv a, const char* buf, int len); jv jv_string_append_str(jv a, const char* str); +jv jv_string_split(jv j, jv sep); jv jv_string_explode(jv j); jv jv_string_implode(jv j);