diff --git a/.gitignore b/.gitignore
index 9a5aced..7d40482 100644
--- a/.gitignore
+++ b/.gitignore
@@ -137,3 +137,8 @@ dist
# Vite logs files
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
+
+# MacOS
+.DS_Store
+src/.DS_Store
+tests/.DS_Store
\ No newline at end of file
diff --git a/docs/STR.md b/docs/STR.md
index 99460bc..a5f8a29 100644
--- a/docs/STR.md
+++ b/docs/STR.md
@@ -21,6 +21,7 @@ brutils str extract "\[(.*?)\]" --text "[one] [two]" --regex
brutils str base64 --text "hello" --mode encode
brutils str urlencode --text "hello world" --mode encode
brutils str html --text "ok" --mode encode
+brutils str leven "kitten" "sitting"
```
## Actions
@@ -39,6 +40,7 @@ brutils str html --text "ok" --mode encode
| `base64` | `brutils str base64 --text [--mode ]` | Encode or decode Base64. |
| `urlencode` | `brutils str urlencode --text [--mode ]` | Encode or decode URL content. |
| `html` | `brutils str html --text [--mode ]` | Encode or decode HTML entities. |
+| `leven` | `brutils str leven ` | Calculates the Levenshtein distance between two strings. |
## Flags
diff --git a/package-lock.json b/package-lock.json
index b1a23c8..15a47bc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@danielarndt0/brutils-cli",
- "version": "1.0.1",
+ "version": "1.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@danielarndt0/brutils-cli",
- "version": "1.0.1",
+ "version": "1.1.0",
"dependencies": {
"archiver": "^7.0.1",
"commander": "^12.1.0",
diff --git a/package.json b/package.json
index 63771e1..ebc8d59 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@danielarndt0/brutils-cli",
- "version": "1.0.1",
+ "version": "1.1.0",
"description": "Production-ready CLI for Brazilian and general developer utilities.",
"type": "module",
"main": "./dist/index.js",
diff --git a/src/cli/commands/register-text-data.ts b/src/cli/commands/register-text-data.ts
index b8cd5c2..65a1af6 100644
--- a/src/cli/commands/register-text-data.ts
+++ b/src/cli/commands/register-text-data.ts
@@ -15,6 +15,7 @@ import {
import {
convertStringCase,
extractText,
+ getLevenshteinDistance,
normalizeText,
padText,
removeAccents,
@@ -58,7 +59,8 @@ export function registerTextDataCommands(program: Command): void {
'brutils str truncate --text "hello world" --max 8 --suffix "..."',
'brutils str replace --text "hello 123" --from "\\\\d+" --with "X" --regex',
'brutils str extract "\\\\[(.*?)\\\\]" --text "[one] [two]" --regex',
- 'brutils str base64 --text "hello" --mode encode'
+ 'brutils str base64 --text "hello" --mode encode',
+ 'brutils str leven "kitten" "sitting"'
])
);
@@ -268,6 +270,15 @@ export function registerTextDataCommands(program: Command): void {
}
);
+ str
+ .description("Calculates the Levenshtein distance between two strings")
+ .command("leven")
+ .argument("")
+ .argument("")
+ .action((a: string, b: string) => {
+ printValue(getLevenshteinDistance(a, b));
+ });
+
const jsonCommand = program
.command("json")
.description("Local JSON formatting, editing and diff helpers.")
diff --git a/src/cli/create-program.ts b/src/cli/create-program.ts
index 57bc70d..0b21e04 100644
--- a/src/cli/create-program.ts
+++ b/src/cli/create-program.ts
@@ -8,7 +8,7 @@ import { registerTextDataCommands } from "./commands/register-text-data.js";
import { rootFooter } from "./shared/help.js";
import { configureProgramUi } from "./ui/output.js";
-const CLI_VERSION = "1.0.1";
+const CLI_VERSION = "1.1.0";
export function buildProgram(): Command {
const program = new Command();
diff --git a/src/services/str/str.service.ts b/src/services/str/str.service.ts
index ddd8ca1..81462e9 100644
--- a/src/services/str/str.service.ts
+++ b/src/services/str/str.service.ts
@@ -251,4 +251,34 @@ export function transformHtmlEntities(
}
return encodeHtmlEntities(value);
+
}
+
+export function getLevenshteinDistance(a: string, b: string): number {
+ a = a.trim()
+ b = b.trim()
+
+ const n = a.length;
+ const m = b.length;
+
+ const dp: number[][] = Array.from({ length: n + 1 }, () =>
+ new Array(m + 1).fill(0)
+ );
+
+ for (let i = 0; i <= n; i++) dp[i]![0] = i;
+ for (let j = 0; j <= m; j++) dp[0]![j] = j;
+
+ for (let i = 1; i <= n; i++) {
+ for (let j = 1; j <= m; j++) {
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
+
+ dp[i]![j] = Math.min(
+ dp[i - 1]![j]! + 1,
+ dp[i]![j - 1]! + 1,
+ dp[i - 1]![j - 1]! + cost
+ );
+ }
+ }
+
+ return dp[n]![m]!;
+}
\ No newline at end of file
diff --git a/tests/str/str.service.spec.ts b/tests/str/str.service.spec.ts
index 9ca9127..ffaa094 100644
--- a/tests/str/str.service.spec.ts
+++ b/tests/str/str.service.spec.ts
@@ -11,10 +11,35 @@ import {
transformHtmlEntities,
transformUrlEncoding,
trimText,
- truncateText
+ truncateText,
+ getLevenshteinDistance
} from "../../src/services/str/index.js";
describe("str service", () => {
+ it("should give me the distance between two strings", () => {
+ expect(getLevenshteinDistance("kitten", "sitting")).toBe(3);
+ });
+
+ it("should give me the distance between two strings", () => {
+ expect(getLevenshteinDistance("book", "back")).toBe(2);
+ });
+
+ it("should give me the distance between two strings", () => {
+ expect(getLevenshteinDistance("cat", "cut")).toBe(1);
+ });
+
+ it("should give me the distance between two strings", () => {
+ expect(getLevenshteinDistance("", "")).toBe(0);
+ });
+
+ it("should give me the distance between two strings", () => {
+ expect(getLevenshteinDistance("Hello".toLowerCase(), "hello")).toBe(0);
+ });
+
+ it("should give me the distance between two strings", () => {
+ expect(getLevenshteinDistance("João", "Joao")).toBe(1);
+ });
+
it("should slugify text", () => {
expect(slugifyText("Hello Cool World")).toBe("hello-cool-world");
});