我如何构建一个以与PostgreSQL相同的方式对Strings进行排序的比较器?

时间:2014-01-06 19:21:46

标签: java string postgresql sorting

我正在编写一个集成测试,它将复杂的order by传递给PostgreSQL,然后检查数据是否以正确的顺序返回。我正在用Java编写这个集成测试,它的String.compareTo方法似乎与PostgreSQL不同。我在PostgreSQL数据库上运行了这个:

SELECT regexp_split_to_table('D d a A c b', ' ') ORDER BY 1;

它回应了这个:

a
A
b
c
d
D

然后我创建了这个单元测试,将其与Java排序的方式进行比较:

import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import org.junit.Test;

import java.util.List;

import static junit.framework.Assert.assertEquals;

public class PostgresqlSortOrderTest {

    @Test
    public void whenJavaSortsStringsThenItIsTheSameAsWhenPostgresqlSortsStrings() {
        List<String> postgresqlOrder = Lists.newArrayList("a", "A", "b", "c", "d", "D");
        Ordering<String> ordering = new Ordering<String>() {
            @Override
            public int compare(String left, String right) {

                return left.compareTo(right);
            }
        };
        List<String> javaOrdering = ordering.sortedCopy(postgresqlOrder);
        assertEquals(postgresqlOrder, javaOrdering);
    }

}

此输出失败:

Expected :[a, A, b, c, d, D]  //postgresql
Actual   :[A, D, a, b, c, d]  //java

我对这里的术语一无所知。我想知道这些不同的String排序的名称,以便我可以更好地沟通。但更重要的是,如何让Java像PostgreSQL一样排序呢?

3 个答案:

答案 0 :(得分:5)

迟到以显示答案,但我担心一个简单的不区分大小写的搜索不一定会做你想要的。

您在搜索中想要的关键字是collation(在更广泛的意义上locales),PostgreSQL依赖底层操作系统来为此提供支持。排序很少是一个简单的逐字符比较。例如,在许多语言环境中,空格被忽略(在en_GB中肯定是这种情况)。

此外,这意味着您可以在不同平台上最终获得不同的排序顺序(取决于Apple或Microsoft是否同意Linus对您所在国家/地区的默认排序)。

有一些讨论是否包含BSD许可库以跨平台提供一致的一组排序是否有意义。但是,这需要做很多工作,这意味着您可以从数据库中的其他操作系统中进行不同的排序。虽然不同的提供商不同意如何处理这个问题,但我担心没有一个简单的解决方案。

您可能想要调查“传统”排序的“C”排序规则。我担心我无法评论Java对正确的语言环境排序的处理 - 而不是我的领域。

答案 1 :(得分:3)

使用比较器:String.CASE_INSENSITIVE_ORDERCollection的任何Strings进行排序。它已在String类中实现。

查看字段摘要http://docs.oracle.com/javase/6/docs/api/java/lang/String.html

答案 2 :(得分:0)

这是一个使用en_GB语言环境匹配PostgreSQL顺序的比较器:

Comparator<String> comparator = (left, right) -> {
    Collator collator = Collator.getInstance(Locale.UK);
    collator.setStrength(Collator.PRIMARY);
    return collator.compare(left.replaceAll("\\p{Punct}", ""), right.replaceAll("\\p{Punct}", ""));
};