实现一个通用的中英文排序工具

Posted BennuCTech

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现一个通用的中英文排序工具相关的知识,希望对你有一定的参考价值。

前言

利用Collator类可以轻松实现排序,但是我们可能有各种model都需要进行排序,这样就会有一个问题,如果单独为每个model写一段排序代码,代码重复量很大。

所以我打算写一个通用的工具,使用泛型+注解+反射的方式来解决。

注解

首先创建注解类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD, ElementType.METHOD)
@Documented
public @interface SortString 

这个注解的作用就是标识哪个字段或函数是用来排序。

工具类

然后是排序工具类,在我这个工具中排序规则是:中文 > 数字 > 英文,这是我们app的需求,大家可以根据自己的需求进行修改。

完整代码如下

public class SimplifiedChineseSorter 
    private static final String SORTINGREGEX = "[^\\\\pL\\\\pN]+|^(The|A|An)\\\\b";
    private static final Collator stringComparator = Collator.getInstance(Locale.SIMPLIFIED_CHINESE);

    public static <T> List<T> sortByProvider(List<T> items, SortStringProvider<T> provider, boolean isIgnoreCase) 
        if (items == null || items.size() <= 0) 
            return null;
        
        return sortList(items, provider, isIgnoreCase);
    

    public static <T> List<T> sortByFieldName(List<T> items, String fieldName, boolean isIgnoreCase) 
        if (items == null || items.size() <= 0) 
            return null;
        
        Field field = getSortStringField(items.get(0).getClass(), fieldName);
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);
        return sortList(items, provider, isIgnoreCase);
    

    public static <T> List<T> sortByFieldAnnotation(List<T> items, boolean isIgnoreCase) 
        if (items == null || items.size() <= 0) 
            return null;
        
        Field field = getSortStringField(items.get(0).getClass());
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);
        return sortList(items, provider, isIgnoreCase);
    

    public static <T> List<T> sortByMethodName(List<T> items, String methodName, boolean isIgnoreCase) 
        if (items == null || items.size() <= 0) 
            return null;
        
        Method method = getSortStringMethod(items.get(0).getClass(), methodName);
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);
        return sortList(items, provider, isIgnoreCase);
    

    public static <T> List<T> sortByMethodAnnotation(List<T> items, boolean isIgnoreCase) 
        if (items == null || items.size() <= 0) 
            return null;
        
        Method method = getSortStringMethod(items.get(0).getClass());
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);
        return sortList(items, provider, isIgnoreCase);
    

    private static <T> List<T> sortList(List<T> items, final SortStringProvider<T> provider, final boolean isIgnoreCase) 
        if(provider == null)
            return items;
        
        final List<T> chinieseList = new ArrayList<T>();
        final List<T> nonChineseList = new ArrayList<T>();
        for (T item : items) 
            if (isChineseCharStart(format(provider.getSortString(item), isIgnoreCase))) 
                chinieseList.add(item);
             else 
                nonChineseList.add(item);
            
        
        List<T> sortedChineseList = Ordering.from(new Comparator<T>() 
            @Override
            public int compare(T lhs, T rhs) 
                return stringComparator.compare(format(provider.getSortString(lhs), isIgnoreCase), format(provider.getSortString(rhs), isIgnoreCase));
            
        ).sortedCopy(chinieseList);
        List<T> sortedNonChineseList = Ordering.from(new Comparator<T>() 
            @Override
            public int compare(T lhs, T rhs) 
                return format(provider.getSortString(lhs), isIgnoreCase).compareTo(format(provider.getSortString(rhs), isIgnoreCase));
            
        ).sortedCopy(nonChineseList);
        sortedChineseList.addAll(sortedNonChineseList);
        return sortedChineseList;
    

    public static <T> Comparator<T> getSortComparatorByProvider(final Class clazz, SortStringProvider<T> provider, boolean isIgnoreCase) 
        return getSortComparator(provider, isIgnoreCase);
    

    public static <T> Comparator<T> getSortComparatorByFieldName(final Class clazz, final String fieldName, boolean isIgnoreCase) 
        Field field = getSortStringField(clazz, fieldName);
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);
        return getSortComparator(provider, isIgnoreCase);
    

    public static <T> Comparator<T> getSortComparatorByFieldAnnotation(final Class clazz, boolean isIgnoreCase) 
        Field field = getSortStringField(clazz);
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(field);
        return getSortComparator(provider, isIgnoreCase);
    

    public static <T> Comparator<T> getSortComparatorByMethodName(final Class clazz, final String methodName, boolean isIgnoreCase) 
        Method method = getSortStringMethod(clazz, methodName);
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);
        return getSortComparator(provider, isIgnoreCase);
    

    public static <T> Comparator<T> getSortComparatorByMethodAnnotation(final Class clazz, boolean isIgnoreCase) 
        Method method = getSortStringMethod(clazz);
        DefualtSortStringProvider<T> provider = new DefualtSortStringProvider<T>(method);
        return getSortComparator(provider, isIgnoreCase);
    

    private static <T> Comparator<T> getSortComparator(final SortStringProvider<T> provider, final boolean isIgnoreCase) 
        return new Comparator<T>() 
            @Override
            public int compare(final T left, final T right) 
                String leftStr = format(provider.getSortString(left), isIgnoreCase);
                String rightStr = format(provider.getSortString(right), isIgnoreCase);
                if (SimplifiedChineseSorter.isChineseCharStart(leftStr) &&
                        SimplifiedChineseSorter.isChineseCharStart(rightStr)) 
                    return stringComparator.compare(leftStr, rightStr);
                 else 
                    return ComparisonChain.start()
                                          .compareTrueFirst(SimplifiedChineseSorter.isChineseCharStart(leftStr),
                                                  SimplifiedChineseSorter.isChineseCharStart(rightStr))
                                          .compare(leftStr, rightStr, Ordering.natural().nullsFirst())
                                          .result();
                
            
        ;
    

    public static boolean isChineseCharStart(String str) 
        return !str.matches("[A-Za-z0-9\\"“”]+.*");
    

    private static <T> Field getSortStringField(Class<T> tClass) 
        Field[] fields = tClass.getDeclaredFields();
        if (fields != null) 
            for (Field field : fields) 
                if (field.isAnnotationPresent(SortString.class) && field.getType() == String.class) 
                    field.setAccessible(true);
                    return field;
                
            
        
        Class superClass = tClass.getSuperclass();
        if(superClass != null && !superClass.equals(Object.class))
            return getSortStringField(superClass);
        
        throw new RuntimeException("The model doesn't have a @SortString field or the type of @SortString field is not a String");
    

    private static <T> Field getSortStringField(Class<T> tClass, String sortFieldName) 
        Field field = null;
        try 
            field = tClass.getDeclaredField(sortFieldName);
         catch (NoSuchFieldException e) 
        
        finally 
            if (field != null && field.getType() == String.class) 
                field.setAccessible(true);
                return field;
            
            Class superClass = tClass.getSuperclass();
            if(superClass != null && !superClass.equals(Object.class))
                return getSortStringField(superClass, sortFieldName);
            
            throw new RuntimeException("The model doesn't have a field named " + sortFieldName);
        
    

    private static <T> Method getSortStringMethod(Class<T> tClass) 
        Method[] methods = tClass.getDeclaredMethods();
        if (methods != null) 
            for (Method method : methods) 
                if (method.isAnnotationPresent(SortString.class) && method.getReturnType() == String.class) 
                    method.setAccessible(true);
                    return method;
                
            
        
        Class superClass = tClass.getSuperclass();
        if(superClass != null && !superClass.equals(Object.class))
            return getSortStringMethod(superClass);
        
        throw new RuntimeException("The model doesn't have a @SortString method or the returnning type of @SortString method is not a String");
    

    private static <T> Method getSortStringMethod(Class<T> tClass, String sortMethodName) 
        Method method = null;
        try 
            method = tClass.getDeclaredMethod(sortMethodName);
         catch (NoSuchMethodException e) 
        
        finally 
            if (method != null && method.getReturnType() == String.class) 
                method.setAccessible(true);
                return method;
            
            Class superClass = tClass.getSuperclass();
            if(superClass != null && !superClass.equals(Object.class))
                return getSortStringMethod以上是关于实现一个通用的中英文排序工具的主要内容,如果未能解决你的问题,请参考以下文章

如何使用滚动片段容器实现通用布局?

Android 逆向Android 逆向通用工具开发 ( Android 平台运行的 cmd 程序类型 | Android 平台运行的 cmd 程序编译选项 | 编译 cmd 可执行程序 )(代码片段

Eclipse 中的通用代码片段或模板

《算法》笔记 3 - 选择排序插入排序希尔排序

几个非常实用的JQuery代码片段

快速排序-递归实现