forked from dude_the_builder/zigstr
Zigstr is a UTF-8 string type for Zig programs.
| src | Updates for latest Zig 0.12.dev; Now using main branch for deps | |
| .gitattributes | Split out of Ziglyph | |
| .gitignore | Now using Zigmod for Ziglyph dependency. | |
| .gitmodules | Added v0.10 branch to Ziglyph submodule | |
| build.zig | Updated module in build.zig | |
| build.zig.zon | Updates for latest Zig 0.12.dev; Now using main branch for deps | |
| LICENSE | Initial commit | |
| README.md | Updated README for tag v0.11.2 | |
Zigstr
A UTF-8 string type.
Zig Version
This code will work with Zig version 0.11 stable.
Adding Zigstr to your Project
Zigstr uses the Zig build system and official package manager, so integration is the same as any other Zig
module. To track the main development branch, in build.zig.zon add:
.dependencies = .{
.zigstr = .{
.url = "https://codeberg.org/dude_the_builder/zigstr/archive/v0.11.2.tar.gz",
},
},
and in your build.zig:
const zigstr = b.dependency("zigstr", .{
.target = target,
.optimize = optimize,
});
// exe, lib, tests, etc.
exe.addModule("zigstr", zigstr.module("zigstr"));
When you now try to build your project, the compiler will produce a hash mismatch error, indicating
the hash that you should add to build.zig.zon to make the build work.
To see available tags click here and when you click
on a tag name, you'll see the link to the tar.gz file under Assets.
With all this, you can now @import("zigstr") in your project.
Ownership
There are two possibilities when creating a new Zigstr:
- You own the bytes, requiring the
deinitmethod to free them. - You don't own the bytes, so
deinitwill not free them.
To create a Zigstr in each of these circumstances:
// Here the slice is []const u8.
varstr=tryZigstr.fromConstBytes(allocator,"Hello");deferstr.deinit();// still need `deinit` to free other resources, but not the passed-in bytes.
// Here the slice is []u8.
varstr=tryZigstr.fromOwnedBytes(allocator,slice);deferstr.deinit();// owned bytes will be freed.
Usage Examples
constZigstr=@import("Zigstr");test"Zigstr README tests"{varallocator=std.testing.allocator;varstr=tryZigstr.fromConstBytes(std.testing.allocator,"Héllo");deferstr.deinit();// Byte count.
tryexpectEqual(@as(usize,6),str.byteLen());// Code point iteration.
varcp_iter=str.codePointIter();varwant=[_]u21{'H',0x00E9,'l','l','o'};vari:usize=0;while(cp_iter.next())|cp|:(i+=1){tryexpectEqual(want[i],cp.code);}// Code point count.
tryexpectEqual(@as(usize,5),trystr.codePointLen());// Collect all code points at once.
constcode_points=trystr.codePoints(allocator);deferallocator.free(code_points);for(code_points,0..)|cp,j|{tryexpectEqual(want[j],cp);}// Grapheme cluster iteration.
vargiter=trystr.graphemeIter();constgc_want=[_][]constu8{"H","é","l","l","o"};i=0;while(giter.next())|gc|:(i+=1){tryexpect(gc.eql(str.bytes(),gc_want[i]));}// Collect all grapheme clusters at once.
tryexpectEqual(@as(usize,5),trystr.graphemeLen());constgcs=trystr.graphemes(allocator);deferallocator.free(gcs);for(gcs,0..)|gc,j|{tryexpect(gc.eql(str.bytes(),gc_want[j]));}// Length by graphemes.
tryexpectEqual(@as(usize,5),trystr.graphemeLen());// Indexing (with negative indexes too.)
tryexpectEqual(trystr.byteAt(0),72);// H
tryexpectEqual(trystr.byteAt(-2),108);// l
tryexpectEqual(trystr.codePointAt(0),'H');tryexpectEqual(trystr.codePointAt(-2),'l');tryexpect((trystr.graphemeAt(0)).eql(str.bytes(),"H"));tryexpect((trystr.graphemeAt(-4)).eql(str.bytes(),"é"));// Copy
varstr2=trystr.copy(allocator);deferstr2.deinit();tryexpect(str.eql(str2));tryexpect(str2.eql("Héllo"));// Empty and obtain owned slice of bytes.
constbytes2=trystr2.toOwnedSlice();deferallocator.free(bytes2);tryexpect(str2.eql(""));tryexpectEqualStrings(bytes2,"Héllo");// Re-initialize a Zigstr.
trystr.reset("foo");// Equality
tryexpect(str.eql("foo"));// exact
tryexpect(!str.eql("fooo"));// lengths
tryexpect(!str.eql("foó"));// combining marks
tryexpect(!str.eql("Foo"));// letter case
// Trimming.
trystr.reset(" Hello");trystr.trimLeft(" ");tryexpect(str.eql("Hello"));trystr.reset("Hello ");trystr.trimRight(" ");tryexpect(str.eql("Hello"));trystr.reset(" Hello ");trystr.trim(" ");tryexpect(str.eql("Hello"));// indexOf / contains / lastIndexOf
trystr.reset("H\u{65}\u{301}llo");// Héllo
tryexpectEqual(str.indexOf("l"),2);tryexpectEqual(str.indexOf("z"),null);tryexpect(str.contains("l"));tryexpect(!str.contains("z"));tryexpectEqual(str.lastIndexOf("l"),3);tryexpectEqual(str.lastIndexOf("z"),null);// Count occurrences of substrings.
tryexpectEqual(str.count("l"),2);tryexpectEqual(str.count("ll"),1);tryexpectEqual(str.count("z"),0);// Tokenization
trystr.reset(" Hello World ");// Token iteration.
vartok_iter=str.tokenIter(" ");tryexpectEqualStrings("Hello",tok_iter.next().?);tryexpectEqualStrings("World",tok_iter.next().?);tryexpect(tok_iter.next()==null);// Collect all tokens at once.
varts=trystr.tokenize(allocator," ");deferallocator.free(ts);tryexpectEqual(@as(usize,2),ts.len);tryexpectEqualStrings("Hello",ts[0]);tryexpectEqualStrings("World",ts[1]);// Split
varsplit_iter=str.splitIter(" ");tryexpectEqualStrings("",split_iter.next().?);tryexpectEqualStrings("Hello",split_iter.next().?);tryexpectEqualStrings("World",split_iter.next().?);tryexpectEqualStrings("",split_iter.next().?);tryexpect(split_iter.next()==null);// Collect all sub-strings at once.
varss=trystr.split(allocator," ");deferallocator.free(ss);tryexpectEqual(@as(usize,4),ss.len);tryexpectEqualStrings("",ss[0]);tryexpectEqualStrings("Hello",ss[1]);tryexpectEqualStrings("World",ss[2]);tryexpectEqualStrings("",ss[3]);// Convenience methods for splitting on newline '\n'.
trystr.reset("Hello\nWorld");variter=str.lineIter();// line iterator
tryexpectEqualStrings(iter.next().?,"Hello");tryexpectEqualStrings(iter.next().?,"World");varlines_array=trystr.lines(allocator);// array of lines without ending \n.
deferallocator.free(lines_array);tryexpectEqualStrings(lines_array[0],"Hello");tryexpectEqualStrings(lines_array[1],"World");// startsWith / endsWith
trystr.reset("Hello World");tryexpect(str.startsWith("Hell"));tryexpect(!str.startsWith("Zig"));tryexpect(str.endsWith("World"));tryexpect(!str.endsWith("Zig"));// Concatenation
trystr.reset("Hello");trystr.concat(" World");tryexpect(str.eql("Hello World"));varothers=[_][]constu8{" is"," the"," tradition!"};trystr.concatAll(&others);tryexpect(str.eql("Hello World is the tradition!"));// replace
trystr.reset("Hello");varreplacements=trystr.replace("l","z");tryexpectEqual(@as(usize,2),replacements);tryexpect(str.eql("Hezzo"));replacements=trystr.replace("z","");tryexpectEqual(@as(usize,2),replacements);tryexpect(str.eql("Heo"));// Append code points.
trystr.reset("Hell");trystr.append('o');tryexpectEqual(@as(usize,5),str.byteLen());tryexpect(str.eql("Hello"));trystr.appendAll(&[_]u21{' ','W','o','r','l','d'});tryexpect(str.eql("Hello World"));// Test for empty string.
tryexpect(!str.isEmpty());// Test for whitespace only (blank) strings.
trystr.reset(" \t ");tryexpect(trystr.isBlank());tryexpect(!str.isEmpty());// Remove grapheme clusters (characters) from strings.
trystr.reset("Hello World");trystr.dropLeft(6);tryexpect(str.eql("World"));trystr.reset("Hello World");trystr.dropRight(6);tryexpect(str.eql("Hello"));// Insert at a grapheme index.
trystr.insert("Hi",0);tryexpect(str.eql("HiHello"));// Remove a sub-string.
trystr.remove("Hi");tryexpect(str.eql("Hello"));trystr.remove("Hello");tryexpect(str.eql(""));// Repeat a string's content.
trystr.reset("*");trystr.repeat(10);tryexpect(str.eql("**********"));trystr.repeat(1);tryexpect(str.eql("**********"));trystr.repeat(0);tryexpect(str.eql(""));// Reverse a string. Note correct handling of Unicode code point ordering.
trystr.reset("Héllo 😊");trystr.reverse();tryexpect(str.eql("😊 olléH"));// You can also construct a Zigstr from coce points.
constcp_array=[_]u21{0x68,0x65,0x6C,0x6C,0x6F};// "hello"
str.deinit();str=tryZigstr.fromCodePoints(allocator,&cp_array);tryexpect(str.eql("hello"));tryexpectEqual(str.codePointLen(),5);// Also create a Zigstr from a slice of strings.
str.deinit();str=tryZigstr.fromJoined(std.testing.allocator,&[_][]constu8{"Hello","World"}," ");tryexpect(str.eql("Hello World"));// Chomp line breaks.
trystr.reset("Hello\n");trystr.chomp();tryexpectEqual(@as(usize,5),str.byteLen());tryexpect(str.eql("Hello"));trystr.reset("Hello\r");trystr.chomp();tryexpectEqual(@as(usize,5),str.byteLen());tryexpect(str.eql("Hello"));trystr.reset("Hello\r\n");trystr.chomp();tryexpectEqual(@as(usize,5),str.byteLen());tryexpect(str.eql("Hello"));// byteSlice, codePointSlice, graphemeSlice, substr
trystr.reset("H\u{0065}\u{0301}llo");// Héllo
constbytes=trystr.byteSlice(1,4);tryexpectEqualSlices(u8,bytes,"\u{0065}\u{0301}");constcps=trystr.codePointSlice(allocator,1,3);deferallocator.free(cps);tryexpectEqualSlices(u21,cps,&[_]u21{'\u{0065}','\u{0301}'});constgs=trystr.graphemeSlice(allocator,1,2);deferallocator.free(gs);tryexpect(gs[0].eql(str.bytes(),"\u{0065}\u{0301}"));// Substrings
varsub=trystr.substr(1,2);tryexpectEqualStrings("\u{0065}\u{0301}",sub);tryexpectEqualStrings(bytes,sub);// Letter case detection.
trystr.reset("hello! 123");tryexpect(trystr.isLower());tryexpect(!trystr.isUpper());trystr.reset("HELLO! 123");tryexpect(trystr.isUpper());tryexpect(!trystr.isLower());// Letter case conversion.
trystr.reset("Héllo World! 123\n");trystr.toLower();tryexpect(str.eql("héllo world! 123\n"));trystr.toUpper();tryexpect(str.eql("HÉLLO WORLD! 123\n"));trystr.reset("tHe (mOviE) 2112\n");trystr.toTitle();tryexpect(str.eql("The (Movie) 2112\n"));// Parsing content.
trystr.reset("123");tryexpectEqual(trystr.parseInt(u8,10),123);trystr.reset("123.456");tryexpectEqual(trystr.parseFloat(f32),123.456);trystr.reset("true");tryexpect(trystr.parseBool());// Truthy == True, T, Yes, Y, On in any letter case.
// Not Truthy == False, F, No, N, Off in any letter case.
tryexpect(trystr.parseTruthy());trystr.reset("TRUE");tryexpect(trystr.parseTruthy());trystr.reset("T");tryexpect(trystr.parseTruthy());trystr.reset("No");tryexpect(!trystr.parseTruthy());trystr.reset("off");tryexpect(!trystr.parseTruthy());// Zigstr implements the std.fmt.format interface.
std.debug.print("Zigstr: {}\n",.{str});}