js-01-slugify
1.000
Challenge · difficulty 1/5
# Slugify a title
Implement an ES module **`solution.js`** exporting a single function:
```js
export function slugify(input) { /* ... */ }
```
Convert a human title string into a URL slug:
- Lowercase the whole string.
- Treat **any character that is not an ASCII letter (`a–z`) or digit (`0–9`) as a separator** —
this includes spaces, punctuation, underscores, and non-ASCII letters.
- Replace each **run** of one or more separators with a **single** hyphen (`-`).
- Strip any leading or trailing hyphens from the result.
Return the resulting slug (a string). An input made entirely of separators returns `""`.
Examples:
```js
slugify("Hello World") // => "hello-world"
slugify(" Hello, World! ") // => "hello-world"
slugify("already-clean") // => "already-clean"
slugify("Top 10 Tips") // => "top-10-tips"
slugify("a---b__c") // => "a-b-c"
slugify("@#$%") // => ""
```
tests/solution.test.js
import { test } from "node:test";
import { strict as assert } from "node:assert";
import { slugify } from "./solution.js";
test("spaces become single hyphens", () => {
assert.equal(slugify("Hello World"), "hello-world");
});
test("punctuation collapses and ends are trimmed", () => {
assert.equal(slugify(" Hello, World! "), "hello-world");
});
test("already-clean input is unchanged", () => {
assert.equal(slugify("already-clean"), "already-clean");
});
test("digits are preserved", () => {
assert.equal(slugify("Top 10 Tips"), "top-10-tips");
});
test("runs of mixed separators collapse to one hyphen", () => {
assert.equal(slugify("a---b__c"), "a-b-c");
});
test("leading and trailing junk is trimmed", () => {
assert.equal(slugify("--Foo Bar--"), "foo-bar");
});
test("all-separator input becomes empty string", () => {
assert.equal(slugify("@#$%"), "");
});
test("empty string stays empty", () => {
assert.equal(slugify(""), "");
});
test("non-ASCII letters act as separators", () => {
assert.equal(slugify("café crème"), "caf-cr-me");
});
System prompt
You are an expert programmer. Solve the task exactly as specified. Output your solution as fenced code blocks using the required file name(s) and the exact function/type signatures requested. Prefer correctness; do not include prose outside code unless asked.
Proposed solution
```js
export function slugify(input) {
let result = input.toLowerCase();
result = result.replace(/[^a-z0-9]/g, ' ');
result = result.replace(/ +/g, '-');
result = result.replace(/^-*|-*$/g, '');
return result;
}
```Test output (stdout)
TAP version 13 # Subtest: spaces become single hyphens ok 1 - spaces become single hyphens --- duration_ms: 0.431491 type: 'test' ... # Subtest: punctuation collapses and ends are trimmed ok 2 - punctuation collapses and ends are trimmed --- duration_ms: 0.06343 type: 'test' ... # Subtest: already-clean input is unchanged ok 3 - already-clean input is unchanged --- duration_ms: 0.04575 type: 'test' ... # Subtest: digits are preserved ok 4 - digits are preserved --- duration_ms: 0.058301 type: 'test' ... # Subtest: runs of mixed separators collapse to one hyphen ok 5 - runs of mixed separators collapse to one hyphen --- duration_ms: 0.075361 type: 'test' ... # Subtest: leading and trailing junk is trimmed ok 6 - leading and trailing junk is trimmed --- duration_ms: 0.04267 type: 'test' ... # Subtest: all-separator input becomes empty string ok 7 - all-separator input becomes empty string --- duration_ms: 0.03943 type: 'test' ... # Subtest: empty string stays empty ok 8 - empty string stays empty --- duration_ms: 0.03607 type: 'test' ... # Subtest: non-ASCII letters act as separators ok 9 - non-ASCII letters act as separators --- duration_ms: 0.05127 type: 'test' ... 1..9 # tests 9 # suites 0 # pass 9 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 27.327092
Reasoning (chain-of-thought)
The task is to implement a `slugify` function that converts a human-readable title string into a URL slug. Let me break down the requirements:
1. Lowercase the whole string
2. Treat any character that is not an ASCII letter (a-z) or digit (0-9) as a separator
3. Replace each run of one or more separators with a single hyphen (-)
4. Strip any leading or trailing hyphens from the result
5. Return the resulting slug (a string)
6. An input made entirely of separators returns ""
Let me think through the implementation:
1. First, convert to lowercase
2. Replace all non-alphanumeric characters with a separator (like a space or hyphen)
3. Replace multiple consecutive separators with a single hyphen
4. Trim leading and trailing hyphens
Here's my approach:
```js
export function slugify(input) {
// Convert to lowercase
let result = input.toLowerCase();
// Replace all non-alphanumeric characters with a space
result = result.replace(/[^a-z0-9]/g, ' ');
// Replace multiple consecutive spaces with a single hyphen
result = result.replace(/ +/g, '-');
// Trim leading and trailing hyphens
result = result.replace(/^-*|-*$/g, '');
return result;
}
```
Wait, let me trace through the examples:
1. `slugify("Hello World")`
- lowercase: "hello world"
- replace non-alphanumeric with space: "hello world" (no change)
- replace multiple spaces with hyphen: "hello-world"
- trim hyphens: "hello-world" ✓
2. `slugify(" Hello, World! ")`
- lowercase: " hello, world! "
- replace non-alphanumeric with space: " hello world "
- replace multiple spaces with hyphen: "hello-world"
- trim hyphens: "hello-world" ✓
3. `slugify("already-clean")`
- lowercase: "already-clean"
- replace non-alphanumeric with space: "already-clean" (no change)
- replace multiple spaces with hyphen: "already-clean"
- trim hyphens: "already-clean" ✓
4. `slugify("Top 10 Tips")`
- lowercase: "top 10 tips"
- replace non-alphanumeric with space: "top 10 tips" (no change)
- replace multiple spaces with hyphen: "top-10-tips"
- trim hyphens: "top-10-tips" ✓
5. `slugify("a---b__c")`
- lowercase: "a---b__c"
- replace non-alphanumeric with space: "a b c"
- replace multiple spaces with hyphen: "a-b-c"
- trim hyphens: "a-b-c" ✓
6. `slugify("@#$%")`
- lowercase: "@#$%"
- replace non-alphanumeric with space: " "
- replace multiple spaces with hyphen: "-"
- trim hyphens: "" ✓
All examples check out! The regex approach handles the requirements correctly.
I could also use a different approach with `split` and `filter`, but the regex method is cleaner and more efficient.
```js
export function slugify(input) {
let result = input.toLowerCase();
result = result.replace(/[^a-z0-9]/g, ' ');
result = result.replace(/ +/g, '-');
result = result.replace(/^-*|-*$/g, '');
return result;
}
```
This solution is straightforward and handles all the edge cases properly.