实现在Scala中进行不区分大小写比较的string类

实现在Scala中进行不区分大小写比较的string类,string,scala,String,Scala,我有很多类的字段是不区分大小写的,我想把这些类的实例放到HashMaps中,并通过字符串不区分大小写来查找它们 每次我想按实例的字符串索引实例或按实例的字符串查找实例时,我都不使用toLowerCase,而是尝试将此逻辑封装在不区分大小写的Estring类中: /** Used to enable us to easily index objects by string, case insensitive * * Note: this class preservse the case of

我有很多类的字段是不区分大小写的,我想把这些类的实例放到HashMaps中,并通过字符串不区分大小写来查找它们

每次我想按实例的字符串索引实例或按实例的字符串查找实例时,我都不使用toLowerCase,而是尝试将此逻辑封装在不区分大小写的Estring类中:

/** 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)
}
有人能建议一个更干净或更好的方法吗

我遇到的一个缺点是在使用junit的assertEquals时,如下所示:

assertEquals("someString", instance.aCaseInsensitiveString)
它失败了,说它期待“一些线索”,但却得到了对案件不敏感的限制

如果我颠倒assertEquals中变量的顺序,那么它就可以工作了,可能是因为它调用了CaseInsensitiveString类上的equals函数。我目前通过保持顺序不变(因此预期的顺序实际上就是预期的顺序)来解决这个问题,但是调用.toString on the Case Insensitive Estring:

assertEquals("someString", instance.aCaseInsensitiveString.toString)
这也有效:

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

我可以添加一个隐式的等于字符串来解决这个问题吗

在我看来,Java的String.equalsIgnoreCase是解决等式问题所需要的。因为JUnit需要一个字符串,所以请确保您的类是从字符串派生的,这样可以解决问题。此外,请记住等式的对称属性,如果a==b,那么b==a,这对编程的含义是,如果有两个对象,obj1和obj2,那么obj1.equals(obj2)==obj2.equals(obj1)


确保您的代码满足这些约束

在Scala 2.8中,您希望定义一个
排序[String]
,并重写
比较
方法来进行不区分大小写的比较。然后,您可以将其传递(或定义隐式val)给任何需要进行比较的函数——所有标准集合都接受
排序[T]
进行比较。

下面是一种更干净的方法,可以使用“代理”和“排序”特性来实现:

没有关于(“字符串”==不区分大小写(“字符串”)问题的帮助

您可以这样隐式转换:

  implicit def sensitize(c: CaseInsensitive) = c.s
  implicit def desensitize(s: String) = CaseInsensitive(s)
这应便于比较:

  assertEquals("Hello"i, "heLLo"i)

下面是一个使用排序的示例(从2.8开始)

res0:List[String]=List(B,F,a,d,e)

定义的对象不区分大小写排序

val orderField = CaseInsensitiveOrdering
orderField:caseinsensitivieordering.type=caseinsensitivieordering$@589643bb

s.sorted(orderField)

res1:List[String]=List(a,B,d,e,F)

我今天遇到了这个问题。这就是我选择解决它的方式:

首先,我声明了一个排序类型的对象来进行排序:

import scala.math.Ordering.StringOrdering
object CaseInsensitiveStringOrdering extends StringOrdering {
  override def compare(x: String, y: String) = {
    String.CASE_INSENSITIVE_ORDER.compare(x,y)
  }
}
接下来,当我创建树映射时,我使用了这个对象,如下所示:

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

这是Scala 2.11.8附带说明的。

您是否想过创建一个有效的特性,以便它能够处理从hashmap获取字符串的逻辑?我没有想到这一点,但不幸的是,我还没有真正理解您的建议。你能再详细解释一下吗,詹姆斯?我会在实例化时将此特性混合到HashMap中吗?谢谢Ken,听起来很有趣,不过我现在还在使用2.7.7。Re equalsIgnoreCase,是的,这就是我想要的功能类型,你建议我如何使用它?我们是从字符串派生出来的,据我所知,字符串是最终的/密封的,不允许扩展它。有趣。。我没听说过代理,它看起来很强大,我会研究这个,thx。代理是如何实现的,它使用反射吗?它还值得使用吗?代理类没有魔法。看看源代码有多简单:啊,好吧,代理将hashCode、equals和toString转发给内部类。出于某种原因,我认为它做的不止这些。请注意,“toString”方法适用于小写版本,它与上面的实现不匹配。你需要覆盖它。避免使用小写字母
toLowerCase
,因为它无法通过“火鸡测试”(用谷歌搜索它,看看字母
'i'
会发生什么变化)。可能使用
String.CASE\u-INSENSITIVE\u-ORDER.compare
,这也可以避免昂贵的字符串复制操作,
String.CASE\u-INSENSITIVE\u-ORDER
也无法通过土耳其测试:o),然后可能使用
Collator.getInstance()
在用户的区域设置中进行正确比较。
s.sorted(orderField)
import scala.math.Ordering.StringOrdering
object CaseInsensitiveStringOrdering extends StringOrdering {
  override def compare(x: String, y: String) = {
    String.CASE_INSENSITIVE_ORDER.compare(x,y)
  }
}
val newMap = new TreeMap[String,AnyRef]()(CaseInsensitiveStringOrdering)