Java 我如何构建一个比较器,以PostgreSQL相同的方式对字符串进行排序?

Java 我如何构建一个比较器,以PostgreSQL相同的方式对字符串进行排序?,java,string,postgresql,sorting,Java,String,Postgresql,Sorting,我正在编写一个集成测试,它将一个复杂的order by传递给PostgreSQL,然后检查数据是否以正确的顺序返回。我正在用Java及其字符串编写这个集成测试。compareTo方法的排序方式似乎与PostgreSQLs不同。我在我的PostgreSQL数据库上运行了以下操作: SELECT regexp_split_to_table('D d a A c b', ' ') ORDER BY 1; 它的答复是: a A b c d D 然后,我创建了这个单元测试,将其与Java排序方式进行比

我正在编写一个集成测试,它将一个复杂的
order by
传递给PostgreSQL,然后检查数据是否以正确的顺序返回。我正在用Java及其
字符串编写这个集成测试。compareTo
方法的排序方式似乎与PostgreSQLs不同。我在我的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);
    }

}

我对这里的术语一无所知。我想知道这些不同字符串排序的名称,以便更好地交流。但更重要的是,如何让Java像PostgreSQL那样排序?

使用comparator:
String.CASE\u-INSENSITIVE\u-ORDER
字符串的
集合进行排序。它已经在
String
类中实现

查看字段摘要

很晚才显示答案,但恐怕简单的不区分大小写的搜索不一定能满足您的需要

您希望在搜索中使用的关键字是(从更广泛的意义上讲),PostgreSQL依赖于底层操作系统来提供支持。排序很少是简单的逐字符比较。例如,在许多地区,空格被忽略(在en_GB中确实如此)

此外,这意味着您可以在不同的平台上获得不同的排序顺序(取决于苹果或微软是否同意Linus对您所在国家的默认排序)

有一些讨论是关于是否有必要包括一个BSD许可的库来提供跨平台的一致订购集。然而,这需要大量的工作,这意味着您可以在数据库中完成与其他操作系统不同的排序。虽然不同的供应商在如何处理这个问题上存在分歧,但恐怕没有一个简单的解决方案


您可能需要研究“传统”排序的“C”排序规则。恐怕我不能评论Java对正确的区域设置排序的处理——不是我的字段。

这里有一个比较器,它使用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}", ""));
};
比较器比较器=(左、右)->{ Collator-Collator=Collator.getInstance(Locale.UK); 折片机设置强度(折片机主); 返回collator.compare(左.replaceAll(\\p{Punct},“”),右.replaceAll(\\p{Punct},“”); };
Java按ASCII顺序执行。PG似乎是按字母顺序排列的,同一个字母的大小写按字母顺序排列(小写<大写)。这就足够编写比较器了。@DaveNewton是真的,但如果有一个库已经有了这样的比较器,我宁愿使用它,也不愿编写自己的比较器。你知道标准API中有一个吗?是的,String.CASE不区分大小写顺序。值得注意的是,postgres中的
ORDER BY
依赖于语言环境,就像Java一样。例如,我的机器上的Postgres 9.3将响应
[A,D,A,b,c,D]
如果您执行
选择regexp\u split\u to_table('D A A c b','')顺序1+1,正如仅供参考的Java以完全相同的方式处理它。它是基于区域设置的,有一个类可以使用。@BrianRoach我想我需要它。我的集成测试以
String.CASE\u INSENSITIVE\u ORDER
在本地通过,但一旦它在我们的CI(不同的操作系统,可能是区域设置)上运行,它就失败了。但是,我不知道如何为默认区域设置获取不区分大小写的collator。你知道怎么做吗?@tieTYT-问题是;您试图跨平台依赖于两个不同系统的行为,这两个系统是基于区域设置的。您要么需要明确地将其管理到匹配的位置,要么选择一端并让它完成工作。如果是我,我需要在查询后在数据库外进行插入排序(我想这就是问题所在),我只需要在Java端进行排序。这里有一个使用Java排序规则的教程:另一个选择可能是重新思考解决问题的方法。
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}", ""));
};