代码之家  ›  专栏  ›  技术社区  ›  waterlooalex

在scala中实现不区分大小写的比较的字符串类

  •  5
  • waterlooalex  · 技术社区  · 15 年前

    我有很多类的字段不区分大小写,我想将这些类的实例放入哈希图中,并通过不区分大小写的字符串查找它们。

    我不想每次都使用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)
    }
    

    有人能提出更清洁或更好的方法吗?

    我遇到的一个缺点是,当使用junit的断言等于以下值时:

    assertEquals("someString", instance.aCaseInsensitiveString)
    

    它失败了,说它应该是“somestring”,但得到了caseinsensitivestring<“somestring”>。

    如果我颠倒断言equals中变量的顺序,那么它就会工作,可能是因为它在类casensitivestring上调用equals函数。我目前通过保持相同的顺序来解决这个问题(所以预期的顺序实际上是预期的顺序),但是调用.toString来处理caseInsensitivestring:

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

    这也是可行的:

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

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

    5 回复  |  直到 8 年前
        1
  •  7
  •   Mitch Blevins    15 年前

    下面是使用“代理”和“有序”特性实现的更清晰的方法:

    // 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”==不区分大小写(“string”)问题没有帮助。

    您可以这样隐式转换:

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

    这样可以方便地进行比较:

      assertEquals("Hello"i, "heLLo"i)
    
        2
  •  3
  •   Ken Bloom    15 年前

    在scala 2.8中,要定义 Ordering[String] ,并重写 compare 方法进行不区分大小写的比较。然后您可以将其传递给任何需要进行比较的函数(或定义隐式VAL)——所有标准集合都接受 Ordering[T] 为了他们的比较。

        3
  •  0
  •   Michael    15 年前

    在我看来,Java的Stange.ErralS信录是为了解决等式问题而需要使用的。由于JUnit需要一个字符串,请确保您的类是从字符串派生的,这样它将解决问题。另外,记住等式的对称性,如果a==b,那么b==a,这意味着如果有两个对象,即obj1和obj2,那么obj1.equals(obj2)==obj2.equals(obj1),那么这就意味着它可以编程。

    确保代码符合这些约束。

        4
  •  0
  •   Ariel    10 年前

    下面是使用排序的示例(从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
    }
    

    定义的对象大小写不敏感排序

    val orderField = CaseInsensitiveOrdering
    

    orderfield:caseinsensitiveordering.type=caseinsensitiveordering$@589643bb

    s.sorted(orderField)
    

    res1:list[string]=列表(a、b、d、e、f)

        5
  •  0
  •   Mike C    8 年前

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

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

    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)
    

    这是与斯卡拉2.11.8 btw。