package cgeo.geocaching.sorting;

import cgeo.geocaching.cgCache;

import org.apache.commons.lang3.StringUtils;

import java.util.Scanner;

/**
 * sorts caches by name
 *
 */
public class NameComparator extends AbstractCacheComparator {

    @Override
    protected boolean canCompare(cgCache cache1, cgCache cache2) {
        return StringUtils.isNotBlank(cache1.name) && StringUtils.isNotBlank(cache2.name);
    }

    @Override
    protected int compareCaches(cgCache cache1, cgCache cache2) {
        // if the caches have a common prefix followed by a number, sort by the numerical value
        // so 2 is before 11, although "11" comes before "2"
        final String prefix = StringUtils.getCommonPrefix(cache1.name, cache2.name);
        if (StringUtils.length(prefix) > 0) {
            final String remaining1 = cache1.name.substring(prefix.length()).trim();
            if (remaining1.length() > 0 && Character.isDigit(remaining1.charAt(0))) {
                final String remaining2 = cache2.name.substring(prefix.length()).trim();
                if (remaining2.length() > 0 && Character.isDigit(remaining2.charAt(0))) {
                    final Integer number1 = (new Scanner(remaining1)).nextInt();
                    final Integer number2 = (new Scanner(remaining2)).nextInt();
                    return number1.compareTo(number2);
                }
            }
        }
        return cache1.name.compareToIgnoreCase(cache2.name);
    }
}

package cgeo.geocaching.sorting;

import cgeo.geocaching.cgCache;

import org.apache.commons.lang3.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * sorts caches by name
 *
 */
public class NameComparator extends AbstractCacheComparator {

    private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+");

    @Override
    protected boolean canCompare(cgCache cache1, cgCache cache2) {
        return StringUtils.isNotBlank(cache1.name) && StringUtils.isNotBlank(cache2.name);
    }

    @Override
    protected int compareCaches(cgCache cache1, cgCache cache2) {
        // if the caches have a common prefix followed by a number, sort by the numerical value
        // so 2 is before 11, although "11" comes before "2"
        final String prefix = StringUtils.getCommonPrefix(cache1.name, cache2.name);
        if (StringUtils.length(prefix) > 0) {
            final String remaining1 = cache1.name.substring(prefix.length()).trim();
            if (remaining1.length() > 0 && Character.isDigit(remaining1.charAt(0))) {
                final String remaining2 = cache2.name.substring(prefix.length()).trim();
                if (remaining2.length() > 0 && Character.isDigit(remaining2.charAt(0))) {
                    final Integer number1 = getNumber(remaining1);
                    final Integer number2 = getNumber(remaining2);
                    return number1.compareTo(number2);
                }
            }
        }
        return cache1.name.compareToIgnoreCase(cache2.name);
    }

    private static Integer getNumber(final String string) {
        Matcher matcher = NUMBER_PATTERN.matcher(string);
        if (matcher.find()) {
            return Integer.valueOf(matcher.group());
        }
        return 0;
    }
}

fix #671, performance of name sorting