string.ha (3438B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use encoding::utf8; 5 use sort::cmp; 6 use strings; 7 8 // Converts all ASCII uppercase characters in a string to their lowercase 9 // representation, returning a new string. The return value must be freed by the 10 // caller. 11 export fn strlower(s: str) str = { 12 let new: []u8 = alloc([], len(s))!; 13 return strlower_buf(s, new); 14 }; 15 16 // Converts all ASCII uppercase characters in a string to their lowercase 17 // representation, returning a new string. The new string data is stored in the 18 // supplied buffer (overwriting any existing contents). The buffer is permitted 19 // to exactly overlap the string. This function will abort if the buffer's 20 // capacity is too small to fit the entire string. 21 export fn strlower_buf(s: str, buf: []u8) str = { 22 let buf = buf[..0]; 23 let it = strings::iter(s); 24 for (let r => strings::next(&it)) { 25 static append(buf, utf8::encoderune(tolower(r))!...)!; 26 }; 27 return strings::fromutf8(buf)!; 28 }; 29 30 // Converts all ASCII lowercase characters in a string to their uppercase 31 // representation, returning a new string. The return value must be freed by the 32 // caller. 33 export fn strupper(s: str) str = { 34 let new: []u8 = alloc([], len(s))!; 35 return strupper_buf(s, new); 36 }; 37 38 // Converts all ASCII lowercase characters in a string to their uppercase 39 // representation, returning a new string. The new string data is stored in the 40 // supplied buffer (overwriting any existing contents). The buffer is permitted 41 // to exactly overlap the string. This function will abort if the buffer's 42 // capacity is too small to fit the entire string. 43 export fn strupper_buf(s: str, buf: []u8) str = { 44 let buf = buf[..0]; 45 let it = strings::iter(s); 46 for (let r => strings::next(&it)) { 47 static append(buf, utf8::encoderune(toupper(r))!...)!; 48 }; 49 return strings::fromutf8(buf)!; 50 }; 51 52 // Compares two strings by their sort order, treating all ASCII capital letters 53 // as their lowercase counterpart (i.e. an ASCII-case-insensitive comparison is 54 // performed). Zero is returned if the strings are equal, a negative value if a 55 // is less than b, or a positive value if a is greater than b. 56 export fn strcasecmp(a: str, b: str) int = { 57 let abs = strings::toutf8(a); 58 let bbs = strings::toutf8(b); 59 for (let i = 0z; i < len(abs) && i < len(bbs); i += 1) { 60 // you know that i am called "the Cast"... 61 // because i *really* love to cast... 62 // sometimes i sit and cast all day... ha ha, but 63 // sometimes i get carried away! 64 let cmp = tolower(abs[i]: rune): u32: int - tolower(bbs[i]: rune): u32: int; 65 if (cmp != 0) return cmp; 66 }; 67 return cmp::sizes(&len(abs), &len(bbs)); 68 }; 69 70 @test fn strcasecmp() void = { 71 let s = strupper("ABC"); 72 defer free(s); 73 assert(s == "ABC"); 74 75 let s = strlower("ABC"); 76 defer free(s); 77 assert(s == "abc"); 78 79 let s = strupper("abc"); 80 defer free(s); 81 assert(s == "ABC"); 82 83 let s = strlower("abc"); 84 defer free(s); 85 assert(s == "abc"); 86 87 let s = strupper("[[["); 88 defer free(s); 89 assert(s == "[[["); 90 91 let s = strlower("[[["); 92 defer free(s); 93 assert(s == "[[["); 94 95 let s = strupper("こ"); 96 defer free(s); 97 assert(s == "こ"); 98 99 let s = strlower("こ"); 100 defer free(s); 101 assert(s == "こ"); 102 103 assert(strcasecmp("ABC", "ABC") == 0); 104 assert(strcasecmp("ABC", "abc") == 0); 105 assert(strcasecmp("ABC", "aB") > 0); 106 assert(strcasecmp("ab", "Abc") < 0); 107 assert(strcasecmp("bcd", "ABC") > 0); 108 assert(strcasecmp("ABC", "[[[") > 0); 109 };