Skip to content

Commit

Permalink
Merge pull request #103 from Philippus/add-azerty-keyboard
Browse files Browse the repository at this point in the history
Add azerty
  • Loading branch information
Philippus authored Oct 7, 2024
2 parents aba45e2 + ab1d839 commit 61e2c2b
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 5 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
Osita is an implementation of the [Optimal String Alignment distance](https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance#Optimal_string_alignment_distance)
algorithm. It implements the standard version of the algorithm and an extension of it where the substitution cost has
been replaced by a function which calculates the keyboard distance between characters using the Euclidean distance
between keys on a QWERTY-keyboard.
between keys on a QWERTY or AZERTY-keyboard.
You can also supply your own substitution cost function.

## Installation
Expand All @@ -26,7 +26,7 @@ import nl.gn0s1s.osita.Osita._

osa("abcde", "abcde") // val res0: Double = 0.0
osa("abcde", "abcd") // val res1: Double = 1.0
osaWithSubstitutionCost("abc", "agc")(weightedKeyboardSubstitutionCost) // val res2: Double = 1.118033988749895
osaWithSubstitutionCost("abc", "agc")(qwertySubstitutionCost) // val res2: Double = 1.118033988749895

```

Expand Down
28 changes: 25 additions & 3 deletions src/main/scala/nl/gn0s1s/osita/Osita.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ object Osita {
.map(_.toCharArray)
}

private val azertyKeyboardGrid: Array[Array[Char]] = {
"""azertyuiop
|qsdfghjklm
|wxcvbn""".stripMargin
.split('\n')
.map(_.toCharArray)
}

private def simpleSubstitutionCost[A](a: A, b: A): Double =
if (a == b) 0.0D else 1.0D

private def findPos(c: Char): (Double, Double) = {
val t = qwertyKeyboardGrid.map(row => row.indexOf(c))
private def findPos(c: Char, keyboardGrid: Array[Array[Char]]): (Double, Double) = {
val t = keyboardGrid.map(row => row.indexOf(c))
val column = t.max
val row = t.indexOf(column)
// compensate for the difference between rows on a keyboard
Expand All @@ -35,7 +43,21 @@ object Osita {
def euclideanDistance(p1: (Double, Double), p2: (Double, Double)): Double =
scala.math.sqrt(scala.math.pow(p1._1 - p2._1, 2) + scala.math.pow(p1._2 - p2._2, 2))

euclideanDistance(findPos(a), findPos(b))
euclideanDistance(findPos(a, qwertyKeyboardGrid), findPos(b, qwertyKeyboardGrid))
}

def qwertySubstitutionCost(a: Char, b: Char): Double = {
def euclideanDistance(p1: (Double, Double), p2: (Double, Double)): Double =
scala.math.sqrt(scala.math.pow(p1._1 - p2._1, 2) + scala.math.pow(p1._2 - p2._2, 2))

euclideanDistance(findPos(a, qwertyKeyboardGrid), findPos(b, qwertyKeyboardGrid))
}

def azertySubstitutionCost(a: Char, b: Char): Double = {
def euclideanDistance(p1: (Double, Double), p2: (Double, Double)): Double =
scala.math.sqrt(scala.math.pow(p1._1 - p2._1, 2) + scala.math.pow(p1._2 - p2._2, 2))

euclideanDistance(findPos(a, azertyKeyboardGrid), findPos(b, azertyKeyboardGrid))
}

// https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance#cite_note-Boytsov-7
Expand Down
5 changes: 5 additions & 0 deletions src/test/scala/nl/gn0s1s/osita/OsitaSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,9 @@ class OsitaSuite extends ScalaCheckSuite {
property("osaWithKeyboard counts transpositions correctly") {
osaWithSubstitutionCost("abc", "acb")(weightedKeyboardSubstitutionCost) == 1
}

property("osaWithKeyboard with azerty works") {
assertEquals(osaWithSubstitutionCost("mop", "nop")(qwertySubstitutionCost), 1D)
assertEquals(osaWithSubstitutionCost("mop", "nop")(azertySubstitutionCost), 2D)
}
}

0 comments on commit 61e2c2b

Please sign in to comment.