diff options
Diffstat (limited to 'stringmetric-cli/source/core/scala/com/rockymadden')
25 files changed, 1064 insertions, 0 deletions
diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/Command.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/Command.scala new file mode 100755 index 0000000..fedc0d9 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/Command.scala @@ -0,0 +1,24 @@ +package com.rockymadden.stringmetric.cli + +/** Defines the traits and provides basic implementations of a command. Commands are always implemented as objects. */ +trait Command { + def help(): Unit + + final def error(error: Throwable, options: OptionMap): Unit = + if (!isUnitTest(options)) { + println(error.getMessage) + sys.exit(1) + } else throw error + + def execute(options: OptionMap): Unit + + final def exit(options: OptionMap): Unit = if (!isUnitTest(options)) sys.exit(0) + + final protected[this] def isDebug(options: OptionMap): Boolean = + (options.contains('d) || (options.contains('debug) && options.get('debug) != "false")) + + final protected[this] def isUnitTest(options: OptionMap): Boolean = + (options.contains('ut) || (options.contains('unitTest) && options.get('unitTest) != "false")) + + def main(args: Array[String]): Unit +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/OptionMap.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/OptionMap.scala new file mode 100755 index 0000000..79aea0b --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/OptionMap.scala @@ -0,0 +1,38 @@ +package com.rockymadden.stringmetric.cli + +import scala.annotation.tailrec + +object OptionMap { + def apply(args: Array[String]): OptionMap = apply(args: _*) + + def apply(varargs: String*): OptionMap = { + @tailrec + def next(om: OptionMap, a: List[String]): OptionMap = { + val double = """^(--[a-zA-Z0-9]+)(=[a-zA-Z0-9\.\-_]+)?""".r + val single = """^(-[a-zA-Z0-9]+)(=[a-zA-Z0-9\.\-_]+)?""".r + val less = """([a-zA-Z0-9/\-_\$\.]+)""".r + + a match { + // Empty, return. + case Nil => om + // Double dash options without value. + case double(k, null) :: t => next(om + (Symbol(k.tail.tail) -> ""), t) + // Double dash options with value. + case double(k, v) :: t => next(om + (Symbol(k.tail.tail) -> v.tail), t) + // Single dash options without value. + case single(k, null) :: t => next(om + (Symbol(k.tail) -> ""), t) + // Single dash options with value. Value is discarded. + case single(k, v) :: t => next(om + (Symbol(k.tail) -> ""), t) + // Dashless options. + case less(v) :: t if v.head != '-' => + if (om.contains('dashless)) + next((om - 'dashless) + ('dashless -> (om('dashless).self + " " + v.trim)), t) + else next(om + ('dashless -> v.trim), t) + // Invalid option, ignore. + case _ :: t => next(om, t) + } + } + + next(Map.empty[Symbol, OptionString], varargs.toList) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/OptionString.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/OptionString.scala new file mode 100755 index 0000000..7a1350d --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/OptionString.scala @@ -0,0 +1,30 @@ +package com.rockymadden.stringmetric.cli + +import scala.language.implicitConversions + +class OptionString(val self: String) + +object OptionString { + implicit def OptionStringToArray(optionString: OptionString): Array[String] = + if (optionString.self.length == 0) Array.empty[String] else optionString.self.split(" ") + + implicit def OptionStringToBigDecimal(optionString: OptionString): BigDecimal = BigDecimal(optionString.self) + + implicit def OptionStringToBigInt(optionString: OptionString): BigInt = BigInt(optionString.self) + + implicit def OptionStringToDouble(optionString: OptionString): Double = optionString.self.toDouble + + implicit def OptionStringToFloat(optionString: OptionString): Float = optionString.self.toFloat + + implicit def OptionStringToInt(optionString: OptionString): Int = optionString.self.toInt + + implicit def OptionStringToLong(optionString: OptionString): Long = optionString.self.toLong + + implicit def OptionStringToShort(optionString: OptionString): Short = optionString.self.toShort + + implicit def OptionStringToString(optionString: OptionString): String = optionString.self + + implicit def StringToOptionString(string: String): OptionString = apply(string) + + def apply(string: String): OptionString = new OptionString(string) +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/package.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/package.scala new file mode 100755 index 0000000..cbaba97 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/package.scala @@ -0,0 +1,13 @@ +package com.rockymadden.stringmetric + +import scala.language.implicitConversions + +/** + * Provides core CLI functionality. Note that some things might look sloppy (e.g. access modifiers, broad imports, + * repetitive imports, etc), but are required because of the way scalascript is ultimately compiled. + */ +package object cli { + type OptionMap = Map[Symbol, OptionString] + + implicit def StringArrayToOptionMap(stringArray: Array[String]): OptionMap = OptionMap(stringArray) +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/metaphonealgorithm.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/metaphonealgorithm.scala new file mode 100755 index 0000000..d0b3812 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/metaphonealgorithm.scala @@ -0,0 +1,41 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.MetaphoneAlgorithm + +/** + * The metaphonealgorithm [[com.rockymadden.stringmetric.cli.Command]]. Returns the phonetic representation of the + * passed string, per the Metaphone algorithm. + */ +object metaphonealgorithm extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 1) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Returns the phonetic representation of the passed string, per the Metaphone algorithm." + ls + ls + + "Syntax:" + ls + + tab + "metaphonealgorithm [Options] string..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = + println(MetaphoneAlgorithm.compute(opts('dashless)).getOrElse("not computable")) +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/metaphonemetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/metaphonemetric.scala new file mode 100755 index 0000000..98ac85c --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/metaphonemetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.MetaphoneMetric + +/** + * The metaphonemetric [[com.rockymadden.stringmetric.cli.Command]]. Compares two strings to determine if they are + * phonetically similarly, per the Metaphone algorithm. + */ +object metaphonemetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares two strings to determine if they are phonetically similarly, per the Metaphone algorithm." + ls + ls + + "Syntax:" + ls + + tab + "metaphonemetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + + println(MetaphoneMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/nysiisalgorithm.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/nysiisalgorithm.scala new file mode 100755 index 0000000..0770ba5 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/nysiisalgorithm.scala @@ -0,0 +1,41 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.NysiisAlgorithm + +/** + * The nysiisalgorithm [[com.rockymadden.stringmetric.cli.Command]]. Returns the phonetic representation of the passed + * string, per the NYSIIS algorithm. + */ +object nysiisalgorithm extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 1) { + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Returns the phonetic representation of the passed string, per the NYSIIS algorithm." + ls + ls + + "Syntax:" + ls + + tab + "nysiisalgorithm [Options] string..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + ) + } + + override def execute(options: OptionMap): Unit = + println(NysiisAlgorithm.compute(options('dashless)).getOrElse("not computable")) +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/nysiismetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/nysiismetric.scala new file mode 100755 index 0000000..95ece48 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/nysiismetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.NysiisMetric + +/** + * The nysiismetric [[com.rockymadden.stringmetric.cli.Command]]. Compares two strings to determine if they are + * phonetically similarly, per the NYSIIS algorithm. + */ +object nysiismetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares two strings to determine if they are phonetically similarly, per the NYSIIS algorithm." + ls + ls + + "Syntax:" + ls + + tab + "nysiismetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + + println(NysiisMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinednysiisalgorithm.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinednysiisalgorithm.scala new file mode 100755 index 0000000..e155cbf --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinednysiisalgorithm.scala @@ -0,0 +1,41 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.RefinedNysiisAlgorithm + +/** + * The refinednysiisalgorithm [[com.rockymadden.stringmetric.cli.Command]]. Returns the phonetic representation of the + * passed string, per the refined NYSIIS algorithm. + */ +object refinednysiisalgorithm extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 1) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Returns the phonetic representation of the passed string, per the refined NYSIIS algorithm." + ls + ls + + "Syntax:" + ls + + tab + "refinednysiisalgorithm [Options] string..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = + println(RefinedNysiisAlgorithm.compute(opts('dashless)).getOrElse("not computable")) +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinednysiismetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinednysiismetric.scala new file mode 100755 index 0000000..3c32291 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinednysiismetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.RefinedNysiisMetric + +/** + * The refinednysiismetric [[com.rockymadden.stringmetric.cli.Command]]. Compares two strings to determine if they are + * phonetically similarly, per the refined NYSIIS algorithm. + */ +object refinednysiismetric extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 2) { + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares two strings to determine if they are phonetically similarly, per the refined NYSIIS algorithm." + ls + ls + + "Syntax:" + ls + + tab + "refinednysiismetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + ) + } + + override def execute(options: OptionMap): Unit = { + val strings: Array[String] = options('dashless) + + println(RefinedNysiisMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinedsoundexalgorithm.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinedsoundexalgorithm.scala new file mode 100755 index 0000000..f5a89a8 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinedsoundexalgorithm.scala @@ -0,0 +1,41 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.RefinedSoundexAlgorithm + +/** + * The refinedsoundexalgorithm [[com.rockymadden.stringmetric.cli.Command]]. Returns the phonetic representation of the + * passed string, per the refined Soundex algorithm. + */ +object refinedsoundexalgorithm extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 1) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Returns the phonetic representation of the passed string, per the refined Soundex algorithm." + ls + ls + + "Syntax:" + ls + + tab + "refinedsoundexalgorithm [Options] string..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = + println(RefinedSoundexAlgorithm.compute(opts('dashless)).getOrElse("not computable")) +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinedsoundexmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinedsoundexmetric.scala new file mode 100755 index 0000000..e5ea4b4 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/refinedsoundexmetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.RefinedSoundexMetric + +/** + * The refinedsoundexmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares two strings to determine if they are + * phonetically similarly, per the refined Soundex algorithm. + */ +object refinedsoundexmetric extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 2) { + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares two strings to determine if they are phonetically similarly, per the refined Soundex algorithm." + ls + ls + + "Syntax:" + ls + + tab + "refinedsoundexmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + ) + } + + override def execute(options: OptionMap): Unit = { + val strings: Array[String] = options('dashless) + + println(RefinedSoundexMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/soundexalgorithm.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/soundexalgorithm.scala new file mode 100755 index 0000000..9883eb3 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/soundexalgorithm.scala @@ -0,0 +1,41 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.SoundexAlgorithm + +/** + * The soundexalgorithm [[com.rockymadden.stringmetric.cli.Command]]. Returns the phonetic representation of the passed + * string, per the Soundex algorithm. + */ +object soundexalgorithm extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 1) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Returns the phonetic representation of the passed string, per the Soundex algorithm." + ls + ls + + "Syntax:" + ls + + tab + "soundexalgorithm [Options] string..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = + println(SoundexAlgorithm.compute(opts('dashless)).getOrElse("not computable")) +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/soundexmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/soundexmetric.scala new file mode 100755 index 0000000..01d070e --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/phonetic/soundexmetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.phonetic + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.phonetic.SoundexMetric + +/** + * The soundexmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares two strings to determine if they are + * phonetically similarly, per the Soundex algorithm. + */ +object soundexmetric extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 2) { + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares two strings to determine if they are phonetically similarly, per the Soundex algorithm." + ls + ls + + "Syntax:" + ls + + tab + "soundexmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + ) + } + + override def execute(options: OptionMap): Unit = { + val strings: Array[String] = options('dashless) + + println(SoundexMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/dicesorensenmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/dicesorensenmetric.scala new file mode 100755 index 0000000..5d0e234 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/dicesorensenmetric.scala @@ -0,0 +1,49 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.DiceSorensenMetric + +/** + * The dicesorensenmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the similarity of two strings using the + * Dice / Sorensen coefficient. + */ +object dicesorensenmetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2 + && opts.contains('n) && (opts('n): Int) >= 1) { + + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the similarity of two strings using the Dice / Sorensen coefficient." + ls + ls + + "Syntax:" + ls + + tab + "dicesorensenmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + + tab + "--n" + ls + + tab + tab + "The n-gram size, traditionally 2." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + val n: Int = opts('n) + + println(DiceSorensenMetric.compare(strings(0), strings(1))(n).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/hammingmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/hammingmetric.scala new file mode 100755 index 0000000..c03293f --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/hammingmetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.HammingMetric + +/** + * The hammingmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the number of characters that two equal + * length strings are different from one another. + */ +object hammingmetric extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 2) { + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the number of characters that two equal length strings are different from one another." + ls + ls + + "Syntax:" + ls + + tab + "hammingmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + ) + } + + override def execute(options: OptionMap): Unit = { + val strings: Array[String] = options('dashless) + + println(HammingMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jaccardmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jaccardmetric.scala new file mode 100755 index 0000000..1f1e123 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jaccardmetric.scala @@ -0,0 +1,49 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.JaccardMetric + +/** + * The jaccardmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the similarity of two strings using the + * Jaccard coefficient. + */ +object jaccardmetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2 + && opts.contains('n) && (opts('n): Int) >= 1) { + + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the similarity of two strings using the Jaccard coefficient." + ls + ls + + "Syntax:" + ls + + tab + "jaccardmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + + tab + "--n" + ls + + tab + tab + "The n-gram size." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + val n: Int = opts('n) + + println(JaccardMetric.compare(strings(0), strings(1))(n).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jarometric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jarometric.scala new file mode 100755 index 0000000..fcb6aa2 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jarometric.scala @@ -0,0 +1,41 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.JaroMetric + +/** The jarometric [[com.rockymadden.stringmetric.cli.Command]]. Compares two strings to calculate the Jaro distance. */ +object jarometric extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 2) { + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares two strings to calculate the Jaro distance." + ls + ls + + "Syntax:" + ls + + tab + "jarometric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + ) + } + + override def execute(options: OptionMap): Unit = { + val strings: Array[String] = options('dashless) + + println(JaroMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jarowinklermetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jarowinklermetric.scala new file mode 100755 index 0000000..b925c2d --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/jarowinklermetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.JaroWinklerMetric + +/** + * The jarowinklermetric [[com.rockymadden.stringmetric.cli.Command]]. Compares two strings to calculate the + * Jaro-Winkler distance. + */ +object jarowinklermetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares two strings to calculate the Jaro-Winkler distance." + ls + ls + + "Syntax:" + ls + + tab + "jarowinklermetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + + println(JaroWinklerMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/levenshteinmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/levenshteinmetric.scala new file mode 100755 index 0000000..6146750 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/levenshteinmetric.scala @@ -0,0 +1,45 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.LevenshteinMetric + +/** + * The levenshteinmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the number of characters that two + * strings are different from one another via insertion, deletion, and substitution. + */ +object levenshteinmetric extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 2) { + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the number of characters that two strings are different from one another via insertion, deletion, " + + "and substitution." + ls + ls + + "Syntax:" + ls + + tab + "levenshteinmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + ) + } + + override def execute(options: OptionMap): Unit = { + val strings: Array[String] = options('dashless) + + println(LevenshteinMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/ngrammetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/ngrammetric.scala new file mode 100755 index 0000000..af0634f --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/ngrammetric.scala @@ -0,0 +1,49 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.NGramMetric + +/** + * The ngrammetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the similarity of two strings using an N-Gram + * similarity index. + */ +object ngrammetric extends Command { + override def main(args: Array[String]): Unit = { + val options: OptionMap = args + + try + if (options.contains('h) || options.contains('help)) { + help() + exit(options) + } else if (options.contains('dashless) && (options('dashless): Array[String]).length == 2 + && options.contains('n) && (options('n): Int) >= 1) { + + execute(options) + exit(options) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, options) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the similarity of two strings using an N-Gram similarity index." + ls + ls + + "Syntax:" + ls + + tab + "ngrammetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and options." + + tab + "--n" + ls + + tab + tab + "The n." + ) + } + + override def execute(options: OptionMap): Unit = { + val strings: Array[String] = options('dashless) + val n: Int = options('n) + + println(NGramMetric.compare(strings(0), strings(1))(n).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/overlapmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/overlapmetric.scala new file mode 100755 index 0000000..2c670c5 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/overlapmetric.scala @@ -0,0 +1,49 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.OverlapMetric + +/** + * The overlapmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the similarity of two strings using the + * overlap coefficient. + */ +object overlapmetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2 + && opts.contains('n) && (opts('n): Int) >= 1) { + + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the similarity of two strings using the overlap coefficient." + ls + ls + + "Syntax:" + ls + + tab + "overlapmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + + tab + "--n" + ls + + tab + tab + "The n-gram size." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + val n: Int = opts('n) + + println(OverlapMetric.compare(strings(0), strings(1))(n).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/ratcliffobershelpmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/ratcliffobershelpmetric.scala new file mode 100755 index 0000000..f69c222 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/ratcliffobershelpmetric.scala @@ -0,0 +1,44 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.RatcliffObershelpMetric + +/** + * The ratcliffobershelpmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the similarity of two strings + * using the Ratcliff / Obershelp similarity index. + */ +object ratcliffobershelpmetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2) { + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the similarity of two strings using the Ratcliff / Obershelp similarity index." + ls + ls + + "Syntax:" + ls + + tab + "ratcliffobershelpmetric [Options] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + + println(RatcliffObershelpMetric.compare(strings(0), strings(1)).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/weightedlevenshteinmetric.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/weightedlevenshteinmetric.scala new file mode 100755 index 0000000..d675db1 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/similarity/weightedlevenshteinmetric.scala @@ -0,0 +1,62 @@ +package com.rockymadden.stringmetric.cli.similarity + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.similarity.WeightedLevenshteinMetric +import scala.math.BigDecimal + +/** + * The weightedlevenshteinmetric [[com.rockymadden.stringmetric.cli.Command]]. Compares the number of characters that + * two strings are different from one another via insertion, deletion, and substitution. Allows the invoker to indicate + * the weight each operation takes. + */ +object weightedlevenshteinmetric extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 2 + && opts.contains('deleteWeight) && (opts('deleteWeight): Double) >= 0 + && opts.contains('insertWeight) && (opts('insertWeight): Double) >= 0 + && opts.contains('substituteWeight) && (opts('substituteWeight): Double) >= 0) { + + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Compares the number of characters that two strings are different from one another via insertion, deletion, " + + "and substitution. Allows the invoker to indicate the weight each operation takes." + ls + ls + + "Syntax:" + ls + + tab + "weightedlevenshteinmetric [Options] --deleteWeight=[double] --insertWeight=[double] --substituteWeight=[double] string1 string2..." + ls + ls + + "Options:" + ls + + tab + "--deleteWeight" + ls + + tab + tab + "The weight given to delete operations." + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + + tab + "--insertWeight" + ls + + tab + tab + "The weight given to insert operations." + + tab + "--substituteWeight" + ls + + tab + tab + "The weight given to substitute operations." + ) + } + + override def execute(opts: OptionMap): Unit = { + val strings: Array[String] = opts('dashless) + val weights = Tuple3[BigDecimal, BigDecimal, BigDecimal]( + opts('deleteWeight), + opts('insertWeight), + opts('substituteWeight) + ) + + println(WeightedLevenshteinMetric.compare(strings(0), strings(1))(weights).getOrElse("not comparable")) + } +} diff --git a/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/tokenization/ngramtokenizer.scala b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/tokenization/ngramtokenizer.scala new file mode 100755 index 0000000..99fdbe5 --- /dev/null +++ b/stringmetric-cli/source/core/scala/com/rockymadden/stringmetric/cli/tokenization/ngramtokenizer.scala @@ -0,0 +1,58 @@ +package com.rockymadden.stringmetric.cli.tokenization + +import com.rockymadden.stringmetric.cli._ +import com.rockymadden.stringmetric.tokenization.NGramTokenizer + +/** + * The ngramtokenizer [[com.rockymadden.stringmetric.cli.Command]]. Returns the N-Gram representation of the passed + * string. + */ +object ngramtokenizer extends Command { + override def main(args: Array[String]): Unit = { + val opts: OptionMap = args + + try + if (opts.contains('h) || opts.contains('help)) { + help() + exit(opts) + } else if (opts.contains('dashless) && (opts('dashless): Array[String]).length == 1 + && opts.contains('n) && (opts('n): Int) >= 1) { + + execute(opts) + exit(opts) + } else throw new IllegalArgumentException("Expected valid syntax. See --help.") + catch { case e: Throwable => error(e, opts) } + } + + override def help(): Unit = { + val ls = sys.props("line.separator") + val tab = " " + + println( + "Returns the N-Gram representation of the passed string." + ls + ls + + "Syntax:" + ls + + tab + "ngramtokenizer [Options] string..." + ls + ls + + "Options:" + ls + + tab + "-h, --help" + ls + + tab + tab + "Outputs description, syntax, and opts." + + tab + "--n" + ls + + tab + tab + "The n." + ) + } + + override def execute(opts: OptionMap): Unit = + NGramTokenizer.tokenize(opts('dashless))(opts('n)) match { + // Implicits are a pain here. + case Some(c) => { + val sb = new StringBuilder + + Range(0, c.length).foreach { i => + sb.append(c(i)) + if (i < c.length - 1) sb.append("|") + } + + println(sb.result()) + } + case None => println("not computable") + } +} |