How do I compare strings for fuzzy or approximate matching in EK9?

← Common String Operations · Ref: Q179

EK9 has a built-in Levenshtein distance operator for fuzzy string comparison. The <~> operator returns the edit distance between two strings as an Integer.

LEVENSHTEIN DISTANCE (<~>)

Compute edit distance between two strings:

  dist <- str1 <~> str2

Returns the minimum number of single-character edits (insertions, deletions, substitutions) needed to transform one string into the other.

IDENTICAL STRINGS

  "hello" <~> "hello" returns 0

SINGLE EDIT

  "kitten" <~> "sitten" returns 1 (one substitution)

PRACTICAL USE: TYPO DETECTION

Use a threshold to detect likely typos:

  if (input <~> expected) <= 2
    stdout.println("Close enough")

REGEX FOR PATTERN MATCHING

For pattern-based matching rather than distance:

  if myString matches /pattern/

See Q37 for string basics. See Q33 for regular expressions.

See Q37 for strings. See Q33 for regular expressions. See Q239 for the <~> fuzzy comparison operator used in ordering and matching.

Example

defines module qa.stringops.fuzzymatch

  defines program
    FuzzyMatchDemo()
      stdout <- Stdout()

      // === LEVENSHTEIN DISTANCE (<~>) ===

      // Identical strings — distance 0
      greeting <- "hello"
      sameGreeting <- "hello"
      dist0 <- greeting <~> sameGreeting
      stdout.println(`hello <~> hello = ${dist0}`)

      // One substitution — distance 1
      original <- "kitten"
      dist1 <- original <~> "sitten"
      stdout.println(`kitten <~> sitten = ${dist1}`)

      // Multiple edits
      dist3 <- original <~> "sitting"
      stdout.println(`kitten <~> sitting = ${dist3}`)

      // Empty string
      planet <- "world"
      distEmpty <- planet <~> ""
      stdout.println(`world <~> empty = ${distEmpty}`)

      // === PRACTICAL: TYPO DETECTION ===

      expected <- "function"
      typo <- "funciton"
      typoDistance <- expected <~> typo
      stdout.println(`Typo distance: ${typoDistance}`)

      typoThreshold <- 2
      if typoDistance <= typoThreshold
        stdout.println("Close enough - likely a typo")

      // === PRACTICAL: FIND CLOSEST MATCH ===

      input <- "colr"
      target1 <- "color"
      target2 <- "collar"
      target3 <- "column"

      d1 <- input <~> target1
      d2 <- input <~> target2
      d3 <- input <~> target3
      stdout.println(`colr <~> color = ${d1}`)
      stdout.println(`colr <~> collar = ${d2}`)
      stdout.println(`colr <~> column = ${d3}`)

      // === REGEX FOR PATTERN MATCHING ===

      testPhrase <- "Hello World"
      if testPhrase matches /.*World$/
        stdout.println("Pattern match: ends with World")

Common mistakes

E50060 — String has no levenshtein() method. Use the <~> operator for Levenshtein distance. See ek9 -h E50060 for details.

Incorrect:

dist1 <- original.levenshtein("sitten")

Correct:

dist1 <- original <~> "sitten"
Other ways to ask this
  • Does EK9 have Levenshtein distance?
  • How do I find similar strings in EK9?
  • How do I detect typos or approximate matches in EK9?

Coming from another language?

Java: no built-in Levenshtein, requires Apache Commons or custom implementation. Python: no built-in, requires python-Levenshtein or difflib.SequenceMatcher. Rust: no built-in, requires strsim crate. Go: no built-in, requires third-party packages. JavaScript: no built-in, requires libraries. Kotlin: no built-in. EK9: built-in <~> operator returns Levenshtein distance as Integer, no libraries needed.

Keywords: text, match, approximate, string, typo, compare, similar, levenshtein, fuzzy, regex, distance