Реализация строкового класса, который делает сравнения без учета регистра в Scala - PullRequest
5 голосов
/ 17 ноября 2009

У меня есть несколько классов с полями, которые должны быть нечувствительными к регистру, и я хотел бы поместить экземпляры этих классов в HashMaps и искать их по строковому регистронезависимому.

Вместо использования toLowerCase каждый раз, когда я хочу индексировать экземпляр по его строке или искать экземпляр по его строке, я вместо этого попытался инкапсулировать эту логику в классе CaseInsensitiveString:

/** Used to enable us to easily index objects by string, case insensitive
 * 
 * Note: this class preservse the case of your string!
 */
class CaseInsensitiveString ( val _value : String ) {
  override def hashCode = _value.toLowerCase.hashCode
  override def equals(that : Any) = that match {
    case other : CaseInsensitiveString => other._value.toLowerCase ==_value.toLowerCase
    case other : String => other.toLowerCase == _value.toLowerCase
    case _ => false
  }
  override def toString = _value
}

object CaseInsensitiveString {
  implicit def CaseInsensitiveString2String(l : CaseInsensitiveString) : String = if ( l ==null ) null else l._value
  implicit def StringToCaseInsensitiveString(s : String) : CaseInsensitiveString = new CaseInsensitiveString(s)

  def apply( value : String ) = new CaseInsensitiveString(value)
  def unapply( l : CaseInsensitiveString) = Some(l._value)
}

Кто-нибудь может предложить более чистый или лучший подход?

Один недостаток, с которым я столкнулся, заключается в использовании asitEquals от junit, например:

assertEquals("someString", instance.aCaseInsensitiveString)

Сбой, говоря, что ожидал "someString", но получил CaseInsensitiveString <"someString">.

Если я переверну порядок переменных в assertEquals, то это сработает, вероятно, потому, что он затем вызывает функцию equals в классе CaseInsensitiveString. В настоящее время я работаю над этим, сохраняя порядок таким же (так что ожидаемый - фактически ожидаемый), но вызываю .toString для CaseInsensitiveString:

assertEquals("someString", instance.aCaseInsensitiveString.toString)

Это тоже работает:

assertEquals(CaseInsensitiveString("someString"), instance.aCaseInsensitiveString)

Могу ли я добавить неявное равенство в String для решения этой проблемы?

Ответы [ 5 ]

7 голосов
/ 17 ноября 2009

Вот более чистый способ реализации с использованием черт "Прокси" и "Упорядоченный":

// http://www.scala-lang.org/docu/files/api/scala/Proxy.html
// http://www.scala-lang.org/docu/files/api/scala/Ordered.html


case class CaseInsensitive(s: String) extends Proxy with Ordered[CaseInsensitive] {
  val self: String = s.toLowerCase
  def compare(other: CaseInsensitive) = self compareTo other.self
  override def toString = s
  def i = this // convenience implicit conversion
}

Нет справки по проблеме ("string" == CaseInsensitive ("String")).

Вы можете неявно конвертировать так:

  implicit def sensitize(c: CaseInsensitive) = c.s
  implicit def desensitize(s: String) = CaseInsensitive(s)

Что должно позволить легко сравнивать:

  assertEquals("Hello"i, "heLLo"i)
3 голосов
/ 17 ноября 2009

В Scala 2.8 вы хотите определить Ordering[String] и переопределить метод compare для сравнения без учета регистра. Затем вы можете передать это (или определить неявное значение val) любой функции, которая должна выполнять сравнение - все стандартные коллекции принимают Ordering[T] для своих сравнений.

0 голосов
/ 07 апреля 2017

Я столкнулся с этим вопросом сегодня. Вот как я решил ее решить:

Сначала я объявил объект типа Ordering для сортировки:

import scala.math.Ordering.StringOrdering
object CaseInsensitiveStringOrdering extends StringOrdering {
  override def compare(x: String, y: String) = {
    String.CASE_INSENSITIVE_ORDER.compare(x,y)
  }
}

Далее, когда я создал свой TreeMap, я использовал этот объект следующим образом:

val newMap = new TreeMap[String,AnyRef]()(CaseInsensitiveStringOrdering)

Это было с Scala 2.11.8.

0 голосов
/ 07 ноября 2014

Вот пример использования Ordering (начиная с версии 2.8)

val s = List( "a", "d", "F", "B", "e")

res0: List [String] = Список (B, F, a, d, e)

object CaseInsensitiveOrdering extends scala.math.Ordering[String] {
    def compare(a:String, b:String) = a.toLowerCase compare b.toLowerCase
}

определенный объект CaseInsensitiveOrdering

val orderField = CaseInsensitiveOrdering

orderField: CaseInsensitiveOrdering.type = CaseInsensitiveOrdering $ @ 589643bb

s.sorted(orderField)

res1: List [String] = Список (a, B, d, e, F)

0 голосов
/ 17 ноября 2009

Мне кажется, что Java String.equalsIgnoreCase - это то, что вам нужно использовать для решения проблемы равенства. Поскольку JUnit ожидает String, убедитесь, что ваш класс является производным от String, и это решит проблему. Кроме того, помните симметричное свойство равенства, если a == b, то b == a, это означает, что если вы имеете два объекта, obj1 и obj2, то obj1.equals (obj2) == obj2. равна (obj1)

Убедитесь, что ваш код соответствует этим ограничениям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...