sub.ha (1507B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 export type end = void; 5 6 fn utf8_byte_len_bounded(iter: *iterator, end: size) size = { 7 for (let i = 0z; i < end; i += 1) { 8 match (next(iter)) { 9 case let r: rune => 10 continue; 11 case done => 12 abort("index exceeds string length"); 13 }; 14 }; 15 return iter.dec.offs; 16 }; 17 18 // Returns a substring in the range [start, end - 1], where each argument is the 19 // index of the Nth rune. If the end argument is given as [[end]], the end of 20 // the substring is the end of the original string. The lifetime of the 21 // substring is the same as that of the original string. 22 // 23 // Note that substringing runewise is not always the correct thing to do, and it 24 // may cause unexpected linguistic errors to arise. You may want to use a 25 // third-party Unicode module instead. 26 export fn sub(s: str, start: size, end: (size | end) = end) str = { 27 let iter = iter(s); 28 let starti = utf8_byte_len_bounded(&iter, start); 29 let endi = match (end) { 30 case let sz: size => 31 assert(start <= sz, "start is higher than end"); 32 yield utf8_byte_len_bounded(&iter, sz - start); 33 case => 34 yield len(s); 35 }; 36 let bytes = toutf8(s); 37 return fromutf8_unsafe(bytes[starti..endi]); 38 }; 39 40 @test fn sub() void = { 41 assert(sub("a string", 2) == "string"); 42 assert(sub("a string", 2, end) == "string"); 43 assert(sub("a string", 0, 1) == "a"); 44 assert(sub("a string", 0, 3) == "a s"); 45 assert(sub("a string", 2, 8) == "string"); 46 assert(sub("a string", 4, 4) == ""); 47 };