Compare commits
No commits in common. "main" and "v1.0.0" have entirely different histories.
4 changed files with 32 additions and 45 deletions
|
@ -14,7 +14,7 @@ _zlugify_ is a library to generate slugs from all types of UTF-8 encoded strings
|
||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
zlugify 1.1.0 is made and tested with zig 0.14.0.
|
ZRM 1.0.0 is made and tested with zig 0.13.0.
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ zlugify 1.1.0 is made and tested with zig 0.14.0.
|
||||||
In your project directory:
|
In your project directory:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ zig fetch --save https://code.zeptotech.net/zedd/zlugify/archive/v1.1.0.tar.gz
|
$ zig fetch --save https://code.zeptotech.net/zedd/zlugify/archive/v1.0.0.tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
In `build.zig`:
|
In `build.zig`:
|
||||||
|
|
|
@ -4,8 +4,8 @@ pub fn build(b: *std.Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
// Add anyascii dependency.
|
// Add anyascii.zig dependency.
|
||||||
const anyascii = b.dependency("anyascii", .{
|
const anyascii = b.dependency("anyascii.zig", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
@ -16,15 +16,15 @@ pub fn build(b: *std.Build) void {
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
// Add anyascii dependency.
|
|
||||||
zlugify.addImport("anyascii", anyascii.module("anyascii"));
|
zlugify.addImport("anyascii", anyascii.module("anyascii"));
|
||||||
|
|
||||||
// Library unit tests.
|
// Library unit tests.
|
||||||
const lib_unit_tests = b.addTest(.{
|
const lib_unit_tests = b.addTest(.{
|
||||||
.root_module = zlugify,
|
.root_source_file = b.path("src/lib.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
lib_unit_tests.root_module.addImport("anyascii", anyascii.module("anyascii"));
|
||||||
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
|
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
|
||||||
|
|
||||||
const test_step = b.step("test", "Run unit tests.");
|
const test_step = b.step("test", "Run unit tests.");
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
.{
|
.{
|
||||||
.name = .zlugify,
|
.name = "zlugify",
|
||||||
.version = "1.1.0",
|
.version = "1.0.0",
|
||||||
|
|
||||||
.fingerprint = 0x60f9ca2959523881,
|
.dependencies = .{
|
||||||
|
.@"anyascii.zig" = .{
|
||||||
|
.url = "https://code.zeptotech.net/zedd/anyascii.zig/archive/v1.1.1.tar.gz",
|
||||||
|
.hash = "1220800d403fc841a4c7b9d09ae8759ae28adff05de33836a3f69f02e8e0ac77bae9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
.dependencies = .{
|
.paths = .{
|
||||||
.anyascii = .{
|
"build.zig",
|
||||||
.url = "https://code.zeptotech.net/zedd/anyascii.zig/archive/v1.2.0.tar.gz",
|
"build.zig.zon",
|
||||||
.hash = "anyascii-1.2.0-rvK7q3iGFABchFPwDMdB5tpj716jR3mukBiuMT-PdD5-",
|
"src",
|
||||||
},
|
"README.md",
|
||||||
},
|
},
|
||||||
|
|
||||||
.paths = .{
|
|
||||||
"build.zig",
|
|
||||||
"build.zig.zon",
|
|
||||||
"src",
|
|
||||||
"README.md",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
35
src/lib.zig
35
src/lib.zig
|
@ -1,26 +1,22 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const anyascii = @import("anyascii");
|
const anyascii = @import("anyascii");
|
||||||
|
|
||||||
/// The values to strip when trimming the string.
|
|
||||||
const valuesToStrip = " \t\r\n\'\"/\\";
|
|
||||||
|
|
||||||
/// Convert the provided string to a slugged version of it.
|
/// Convert the provided string to a slugged version of it.
|
||||||
/// With this function, you can set the separator to use.
|
/// With this function, you can set the separator to use.
|
||||||
pub fn slugifySeparator(allocator: std.mem.Allocator, str: []const u8, separator: u8) ![]u8 {
|
pub fn slugifySeparator(allocator: std.mem.Allocator, str: []const u8, separator: u8) ![]u8 {
|
||||||
// Convert the provided UTF-8 string to ASCII.
|
// Trim the provided string.
|
||||||
const fullResult = try anyascii.utf8ToAscii(allocator, str);
|
const trimmed = std.mem.trim(u8, str, " \xA0\t\r\n\'\"/\\");
|
||||||
const startShift = fullResult.len - std.mem.trimLeft(u8, fullResult, valuesToStrip).len;
|
// Convert UTF-8 string to ASCII.
|
||||||
const endShift = fullResult.len - std.mem.trimRight(u8, fullResult, valuesToStrip).len;
|
const result = try anyascii.utf8ToAscii(allocator, trimmed);
|
||||||
const result = fullResult[startShift..fullResult.len - endShift];
|
|
||||||
|
|
||||||
// Check each char to remove them / replace them by their slugged version if needed.
|
// Check each char to remove them / replace them by their slugged version if needed.
|
||||||
var previousIsSeparator = true; // Setting it to true at start forbids the result to start with a separator.
|
var previousIsSeparator = true; // Setting it to true at start forbids the result to start with a separator.
|
||||||
var shift: usize = 0;
|
var shift: usize = 0;
|
||||||
for (0..result.len, result) |i, char| {
|
for (0..result.len, result) |i, char| {
|
||||||
if (char == ' ' or char == '\t' or char == '\r' or char == '\n' or char == '\'' or char == '"' or char == '/' or char == '\\') {
|
if (char == ' ' or char == '\xA0' or char == '\t' or char == '\r' or char == '\n' or char == '\'' or char == '"' or char == '/' or char == '\\') {
|
||||||
// Whitespace-like character: replace it by a dash, or remove it if the previous character is a dash.
|
// Whitespace-like character: replace it by a dash, or remove it if the previous character is a dash.
|
||||||
if (!previousIsSeparator) {
|
if (!previousIsSeparator) {
|
||||||
fullResult[i - shift] = separator;
|
result[i - shift] = separator;
|
||||||
previousIsSeparator = true;
|
previousIsSeparator = true;
|
||||||
} else {
|
} else {
|
||||||
// To remove the current character, we just shift all future written characters.
|
// To remove the current character, we just shift all future written characters.
|
||||||
|
@ -30,7 +26,7 @@ pub fn slugifySeparator(allocator: std.mem.Allocator, str: []const u8, separator
|
||||||
// In the general case, we keep alphanumeric characters and all the rest is shifted.
|
// In the general case, we keep alphanumeric characters and all the rest is shifted.
|
||||||
if (std.ascii.isAlphanumeric(char)) {
|
if (std.ascii.isAlphanumeric(char)) {
|
||||||
// Convert the ASCII character to its lowercased version.
|
// Convert the ASCII character to its lowercased version.
|
||||||
fullResult[i - shift] = std.ascii.toLower(char);
|
result[i - shift] = std.ascii.toLower(char);
|
||||||
previousIsSeparator = false;
|
previousIsSeparator = false;
|
||||||
} else {
|
} else {
|
||||||
shift += 1;
|
shift += 1;
|
||||||
|
@ -39,18 +35,12 @@ pub fn slugifySeparator(allocator: std.mem.Allocator, str: []const u8, separator
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we removed characters, free the remaining unused memory.
|
// If we removed characters, free the remaining unused memory.
|
||||||
if (shift > 0 or startShift > 0 or endShift > 0) {
|
if (shift > 0) {
|
||||||
if (!allocator.resize(fullResult, result.len - shift)) {
|
_ = allocator.resize(result, result.len - shift);
|
||||||
// In case of a failed resize, reallocate.
|
|
||||||
defer allocator.free(fullResult);
|
|
||||||
const resultAlloc = try allocator.alloc(u8, result.len - shift);
|
|
||||||
@memcpy(resultAlloc, fullResult[0..result.len - shift]);
|
|
||||||
return resultAlloc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the result without the shifted characters.
|
// Return the result without the shifted characters.
|
||||||
return fullResult[0..result.len - shift];
|
return result[0..result.len - shift];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the provided string to a slugged version of it with the default '-' separator.
|
/// Convert the provided string to a slugged version of it with the default '-' separator.
|
||||||
|
@ -62,7 +52,6 @@ test slugify {
|
||||||
try testSlugify("this-is-a-test", " This is a test.\t\n");
|
try testSlugify("this-is-a-test", " This is a test.\t\n");
|
||||||
try testSlugify("something-else", "SôMÈThing \t ÉLSÈ");
|
try testSlugify("something-else", "SôMÈThing \t ÉLSÈ");
|
||||||
try testSlugify("slugify-a-string", "𝒔𝒍𝒖𝒈𝒊𝒇𝒚 𝒂 𝒔𝒕𝒓𝒊𝒏𝒈");
|
try testSlugify("slugify-a-string", "𝒔𝒍𝒖𝒈𝒊𝒇𝒚 𝒂 𝒔𝒕𝒓𝒊𝒏𝒈");
|
||||||
try testSlugify("a", "à ");
|
|
||||||
|
|
||||||
try testSlugify("blosse-shenzhen", "Blöße 深圳");
|
try testSlugify("blosse-shenzhen", "Blöße 深圳");
|
||||||
try testSlugify("qiyu-xian", "埼玉 県");
|
try testSlugify("qiyu-xian", "埼玉 県");
|
||||||
|
@ -77,7 +66,7 @@ test slugify {
|
||||||
try testSlugify("toi-yeu-nhung-chu-ky-lan", "tôi yêu những chú kỳ lân");
|
try testSlugify("toi-yeu-nhung-chu-ky-lan", "tôi yêu những chú kỳ lân");
|
||||||
}
|
}
|
||||||
/// Test slugify function.
|
/// Test slugify function.
|
||||||
fn testSlugify(expected: []const u8, toSlugify: []const u8) !void {
|
pub fn testSlugify(expected: []const u8, toSlugify: []const u8) !void {
|
||||||
const slug = try slugify(std.testing.allocator, toSlugify);
|
const slug = try slugify(std.testing.allocator, toSlugify);
|
||||||
defer std.testing.allocator.free(slug);
|
defer std.testing.allocator.free(slug);
|
||||||
|
|
||||||
|
@ -88,7 +77,7 @@ test slugifySeparator {
|
||||||
try testSlugifySeparator("something_else", "SôMÈThing \t ÉLSÈ", '_');
|
try testSlugifySeparator("something_else", "SôMÈThing \t ÉLSÈ", '_');
|
||||||
}
|
}
|
||||||
/// Test slugifySeparator function.
|
/// Test slugifySeparator function.
|
||||||
fn testSlugifySeparator(expected: []const u8, toSlugify: []const u8, separator: u8) !void {
|
pub fn testSlugifySeparator(expected: []const u8, toSlugify: []const u8, separator: u8) !void {
|
||||||
const slug = try slugifySeparator(std.testing.allocator, toSlugify, separator);
|
const slug = try slugifySeparator(std.testing.allocator, toSlugify, separator);
|
||||||
defer std.testing.allocator.free(slug);
|
defer std.testing.allocator.free(slug);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue