質問

私は書く必要があるJavaコンパレータのクラスが比較されている文字列が一つの問題ではないでしょうか。場合には二つの文字列で比較は同じで最初と最後の文字列が同じ、真ん中の部分が異なる整数であり、その比較に基づく数値の整数です。例えば、以下のような文字列が起きている順序で表示されます:

  • 年次決算
  • bbb3ccc
  • bbb12ccc
  • ccc11
  • ddd
  • eee3ddd jpeg2000eee
  • eee12ddd jpeg2000eee

ご覧のとおりであったり、他の整数の文字列きないだけで正規表現は利用行為の整数値です。おうと思っていただ歩いているだけなのに、文字列の先頭からまでを見たいの少ない試合でし歩から終了までを見たいの少ない試合を比較するとビット中の正規表現"[0-9]+の場合で比較して数値比較、そうでないという語彙の比較です。

ありそうです。

更新 いえるのではないかと思っているという保証はその他の数字の文字列の場合についてお答えください空間に買い替えることができるようにしたものが違います。

役に立ちましたか?

解決

のAlphanumアルゴリズム

ウェブサイトから

"人にソート文字列を数字とは違ったソフトウェアです。多ソートアルゴリズムの比較ASCII値は、順序付けれる人。こちらはどいいじゃないか初書きぐらい。"

編集:こちらはへのリンク Javaコンパレータの実装 からのサポートして参りました。

他のヒント

少し興味深い課題で、楽しかった解決します。

この問題:

String[] strs =
{
  "eee 5 ddd jpeg2001 eee",
  "eee 123 ddd jpeg2000 eee",
  "ddd",
  "aaa 5 yy 6",
  "ccc 555",
  "bbb 3 ccc",
  "bbb 9 a",
  "",
  "eee 4 ddd jpeg2001 eee",
  "ccc 11",
  "bbb 12 ccc",
  "aaa 5 yy 22",
  "aaa",
  "eee 3 ddd jpeg2000 eee",
  "ccc 5",
};

Pattern splitter = Pattern.compile("(\\d+|\\D+)");

public class InternalNumberComparator implements Comparator
{
  public int compare(Object o1, Object o2)
  {
    // I deliberately use the Java 1.4 syntax, 
    // all this can be improved with 1.5's generics
    String s1 = (String)o1, s2 = (String)o2;
    // We split each string as runs of number/non-number strings
    ArrayList sa1 = split(s1);
    ArrayList sa2 = split(s2);
    // Nothing or different structure
    if (sa1.size() == 0 || sa1.size() != sa2.size())
    {
      // Just compare the original strings
      return s1.compareTo(s2);
    }
    int i = 0;
    String si1 = "";
    String si2 = "";
    // Compare beginning of string
    for (; i < sa1.size(); i++)
    {
      si1 = (String)sa1.get(i);
      si2 = (String)sa2.get(i);
      if (!si1.equals(si2))
        break;  // Until we find a difference
    }
    // No difference found?
    if (i == sa1.size())
      return 0; // Same strings!

    // Try to convert the different run of characters to number
    int val1, val2;
    try
    {
      val1 = Integer.parseInt(si1);
      val2 = Integer.parseInt(si2);
    }
    catch (NumberFormatException e)
    {
      return s1.compareTo(s2);  // Strings differ on a non-number
    }

    // Compare remainder of string
    for (i++; i < sa1.size(); i++)
    {
      si1 = (String)sa1.get(i);
      si2 = (String)sa2.get(i);
      if (!si1.equals(si2))
      {
        return s1.compareTo(s2);  // Strings differ
      }
    }

    // Here, the strings differ only on a number
    return val1 < val2 ? -1 : 1;
  }

  ArrayList split(String s)
  {
    ArrayList r = new ArrayList();
    Matcher matcher = splitter.matcher(s);
    while (matcher.find())
    {
      String m = matcher.group(1);
      r.add(m);
    }
    return r;
  }
}

Arrays.sort(strs, new InternalNumberComparator());

このアルゴリズムの必要性試験うですが、行動になります。

[編集]かもコメントするほど明快である。がいかに答えようのコードにこ---もうメンバーとして含まれており、出発の拠点あるアイデア。

イアン-Griffiths MicrosoftはC#の実施を呼ん 自然選別.への移植Javaはかなり簡単に、よからうというものだった。

更新: があるようでJava例 eekboom この"compareNatural"をご用意しておcomparerをひとつに違いありません。

の実施を提案致しますここでは簡単に、効率的です。な配当としてメモリを、直接または間接に正規表現を使用して又は方法などの部分文字列()、(),toCharArray()など。

この実装となっているものの文字列検索のための最初の文字とは異なる、最大速なだけ電源をオンにする"という特殊加工中です。特定の番号比較の実行時にこれらの文字の両方ができるようにしました。サイドの効果この実装は、桁はこれ以上その他の文字が、逆にデフォルトの際の字句ます。

public static final int compareNatural (String s1, String s2)
{
   // Skip all identical characters
   int len1 = s1.length();
   int len2 = s2.length();
   int i;
   char c1, c2;
   for (i = 0, c1 = 0, c2 = 0; (i < len1) && (i < len2) && (c1 = s1.charAt(i)) == (c2 = s2.charAt(i)); i++);

   // Check end of string
   if (c1 == c2)
      return(len1 - len2);

   // Check digit in first string
   if (Character.isDigit(c1))
   {
      // Check digit only in first string 
      if (!Character.isDigit(c2))
         return(1);

      // Scan all integer digits
      int x1, x2;
      for (x1 = i + 1; (x1 < len1) && Character.isDigit(s1.charAt(x1)); x1++);
      for (x2 = i + 1; (x2 < len2) && Character.isDigit(s2.charAt(x2)); x2++);

      // Longer integer wins, first digit otherwise
      return(x2 == x1 ? c1 - c2 : x1 - x2);
   }

   // Check digit only in second string
   if (Character.isDigit(c2))
      return(-1);

   // No digits
   return(c1 - c2);
}

を実現んjavaものをご覧になることができなどStrCmpLogicalWます。これがExplorerに使うファイル名です。楽しみがさらに広がるでしょうのワインの実施 こちらの.

分割の文字列の文字、数字、"foo12バー"となりのリスト("foo"は、12日、"bar"を、その利用の一覧を並べ替えます。このように、数字はご注文いただけます順、アルファベッ.

が浮かび上がった非常に簡単な実装にはJava正規表現を使用して:

public static Comparator<String> naturalOrdering() {
    final Pattern compile = Pattern.compile("(\\d+)|(\\D+)");
    return (s1, s2) -> {
        final Matcher matcher1 = compile.matcher(s1);
        final Matcher matcher2 = compile.matcher(s2);
        while (true) {
            final boolean found1 = matcher1.find();
            final boolean found2 = matcher2.find();
            if (!found1 || !found2) {
                return Boolean.compare(found1, found2);
            } else if (!matcher1.group().equals(matcher2.group())) {
                if (matcher1.group(1) == null || matcher2.group(1) == null) {
                    return matcher1.group().compareTo(matcher2.group());
                } else {
                    return Integer.valueOf(matcher1.group(1)).compareTo(Integer.valueOf(matcher2.group(1)));
                }
            }
        }
    };
}

ここではどのような著作物:

final List<String> strings = Arrays.asList("x15", "xa", "y16", "x2a", "y11", "z", "z5", "x2b", "z");
strings.sort(naturalOrdering());
System.out.println(strings);

[x2a,x2b,×15,xa y11,y16,z,z,z5]

Alphanum algrothimは、それに合致しない要件のプロジェクトの仕事をしています。いので負の数部で"年"、小数部で"正しくこちらは実施しました。意思をよろしくお願いいたします。

public class StringAsNumberComparator implements Comparator<String> {

    public static final Pattern NUMBER_PATTERN = Pattern.compile("(\\-?\\d+\\.\\d+)|(\\-?\\.\\d+)|(\\-?\\d+)");

    /**
     * Splits strings into parts sorting each instance of a number as a number if there is
     * a matching number in the other String.
     * 
     * For example A1B, A2B, A11B, A11B1, A11B2, A11B11 will be sorted in that order instead
     * of alphabetically which will sort A1B and A11B together.
     */
    public int compare(String str1, String str2) {
        if(str1 == str2) return 0;
        else if(str1 == null) return 1;
        else if(str2 == null) return -1;

        List<String> split1 = split(str1);
        List<String> split2 = split(str2);
        int diff = 0;

        for(int i = 0; diff == 0 && i < split1.size() && i < split2.size(); i++) {
            String token1 = split1.get(i);
            String token2 = split2.get(i);

            if((NUMBER_PATTERN.matcher(token1).matches() && NUMBER_PATTERN.matcher(token2).matches()) {
                diff = (int) Math.signum(Double.parseDouble(token1) - Double.parseDouble(token2));
            } else {
                diff = token1.compareToIgnoreCase(token2);
            }
        }
        if(diff != 0) {
            return diff;
        } else {
            return split1.size() - split2.size();
        }
    }

    /**
     * Splits a string into strings and number tokens.
     */
    private List<String> split(String s) {
        List<String> list = new ArrayList<String>();
        try (Scanner scanner = new Scanner(s)) {
            int index = 0;
            String num = null;
            while ((num = scanner.findInLine(NUMBER_PATTERN)) != null) {
                int indexOfNumber = s.indexOf(num, index);
                if (indexOfNumber > index) {
                    list.add(s.substring(index, indexOfNumber));
                }
                list.add(num);
                index = indexOfNumber + num.length();
            }
            if (index < s.length()) {
                list.add(s.substring(index));
            }
        }
        return list;
    }
}

PS.たいと思ったのjava.lang.文字列になります。split()メソッドを使用"lookahead/lookbehind"のトークンがなかったが、正規表現した。

興味深い問題で、ここでの私の提案した解

import java.util.Collections;
import java.util.Vector;

public class CompareToken implements Comparable<CompareToken>
{
    int valN;
    String valS;
    String repr;

    public String toString() {
    return repr;
    }

    public CompareToken(String s) {
    int l = 0;
    char data[] = new char[s.length()];
    repr = s;
    valN = 0;
    for (char c : s.toCharArray()) {
        if(Character.isDigit(c))
        valN = valN * 10 + (c - '0');
        else
        data[l++] = c;
    }

    valS = new String(data, 0, l);
    }

    public int compareTo(CompareToken b) {
    int r = valS.compareTo(b.valS);
    if (r != 0)
        return r;

    return valN - b.valN;
    }


    public static void main(String [] args) {
    String [] strings = {
        "aaa",
        "bbb3ccc",
        "bbb12ccc",
        "ccc 11",
        "ddd",
        "eee3dddjpeg2000eee",
        "eee12dddjpeg2000eee"
    };

    Vector<CompareToken> data = new Vector<CompareToken>();
    for(String s : strings)
        data.add(new CompareToken(s));
    Collections.shuffle(data);

    Collections.sort(data);
    for (CompareToken c : data)
        System.out.println ("" + c);
    }

}

事前の発見ではこのスレッドは、実は同様の解決策です。恐らく私の戦略を探し出すも異なる構文です。同様に、構文解析の二つの文字列の比較、分割してるのは、こちらの配列を分割する文字列で継続す。

...
var regex = /(\d+)/g,
    str1Components = str1.split(regex),
    str2Components = str2.split(regex),
...

にて、 'hello22goodbye33'=>['こんにちは',22,'さよなら',33];このように、中を歩くことができる配列要素をペアでの間に文字列1と文字列2,いくつかの型強制など、この要素も多数?), 比較として使用しています。

作例はこちら http://jsfiddle.net/F46s6/3/

また、現在サポートは整数タイプのものの取り扱い数値になるもの。

私の2つのセント.するものでした。私は主に、利用ファイル名.

    private final boolean isDigit(char ch)
        {
            return ch >= 48 && ch <= 57;
        }


        private int compareNumericalString(String s1,String s2){

            int s1Counter=0;
            int s2Counter=0;
            while(true){
                if(s1Counter>=s1.length()){
                    break;
                }
                if(s2Counter>=s2.length()){
                    break;
                }
                char currentChar1=s1.charAt(s1Counter++);
                char currentChar2=s2.charAt(s2Counter++);
                if(isDigit(currentChar1) &&isDigit(currentChar2)){
                    String digitString1=""+currentChar1;
                    String digitString2=""+currentChar2;
                    while(true){
                        if(s1Counter>=s1.length()){
                            break;
                        }
                        if(s2Counter>=s2.length()){
                            break;
                        }

                        if(isDigit(s1.charAt(s1Counter))){
                            digitString1+=s1.charAt(s1Counter);
                            s1Counter++;
                        }

                        if(isDigit(s2.charAt(s2Counter))){
                            digitString2+=s2.charAt(s2Counter);
                            s2Counter++;
                        }

                        if((!isDigit(s1.charAt(s1Counter))) && (!isDigit(s2.charAt(s2Counter)))){
                            currentChar1=s1.charAt(s1Counter);
                            currentChar2=s2.charAt(s2Counter);
                            break;
                        }
                    }
                    if(!digitString1.equals(digitString2)){
                        return Integer.parseInt(digitString1)-Integer.parseInt(digitString2);
                    }
                }

                if(currentChar1!=currentChar2){
                    return currentChar1-currentChar2;
                }

            }
            return s1.compareTo(s2);
        }

と思いますのでいいの比較文字による文字です。鷲掴みにキャラクターの場合は数字、掴み、その組み換えを文字単一の文字列を数値に変換で int.繰り返しの文字列は、次のと比較しました。

答え:に基づく文脈できるようになっているかどうかを通知すぐにあるアットホームなや汚れたコードのための個人的な使用、またはキーの一部にゴールドマン-サックスの最新の内部の会計ソフトウェアで開くよ"ということ:eww.ことになるでファンキーなソートアルゴリズム;利用するようにしてないかなと思ったのがきっかけサービス"twisty"ができます。

長い回答:

の二つの課題とされており、見るだけでなく心のお場合には、正.非公式にしてください速いっていることを確認してくださいごのアルゴリズムは 総合順序.

(もちろんだの分別により約100項目にできるのではないでしょうかを軽視するものとする。) 性能に関としての速度をコンパレータで最大規模となる因子の速度おうとうアルゴリズムの"理想"の典型的な。このケースでは、コンパレータの速度によって、サイズの文字列になります。文字列のような短いため、んを占めているサイズの一覧です。

回転毎に文字列を文字列-数字-文字列のタプルを仕分けのこのリストタプルとは別の回答を失の一部の場合、これまで明らかい文字列に複数の番号。

その他の問題が正.具体的には、場合にはアルゴリズムをご説が許可A>B>...>、そしてソートする非決定性.お場合は、恐れることができないことを証明します。あの解析事例など

  aa 0 aa
  aa 23aa
  aa 2a3aa
  aa 113aa
  aa 113 aa
  a 1-2 a
  a 13 a
  a 12 a
  a 2-3 a
  a 21 a
  a 2.3 a

この問題をjava解したい人のためのスカラ液

object Alphanum {

   private[this] val regex = "((?<=[0-9])(?=[^0-9]))|((?<=[^0-9])(?=[0-9]))"

   private[this] val alphaNum: Ordering[String] = Ordering.fromLessThan((ss1: String, ss2: String) => (ss1, ss2) match {
     case (sss1, sss2) if sss1.matches("[0-9]+") && sss2.matches("[0-9]+") => sss1.toLong < sss2.toLong
     case (sss1, sss2) => sss1 < sss2
   })

   def ordering: Ordering[String] = Ordering.fromLessThan((s1: String, s2: String) => {
     import Ordering.Implicits.infixOrderingOps
     implicit val ord: Ordering[List[String]] = Ordering.Implicits.seqDerivedOrdering(alphaNum)

     s1.split(regex).toList < s2.split(regex).toList
   })

}

ようにしてリストの組み合わせから成るアルファの数値文字列(例C22、C3、C5など)、アルファの文字列(例えば、H、Rなど)や桁(例えば、99,45など)を必要とするソートの順に、C3、C5,C22,H,R,45,99.また、複製を必要とする除去がよかったで取得する単一入力します。

私もいないはずの文字列とい秩序のオブジェクトを使用する特定分野のオブジェクトを取得しめるという事です。

シうというのは:

SortedSet<Code> codeSet;
codeSet = new TreeSet<Code>(new Comparator<Code>() {

private boolean isThereAnyNumber(String a, String b) {
    return isNumber(a) || isNumber(b);
}

private boolean isNumber(String s) {
    return s.matches("[-+]?\\d*\\.?\\d+");
}

private String extractChars(String s) {
    String chars = s.replaceAll("\\d", "");
    return chars;
}

private int extractInt(String s) {
    String num = s.replaceAll("\\D", "");
    return num.isEmpty() ? 0 : Integer.parseInt(num);
}

private int compareStrings(String o1, String o2) {

    if (!extractChars(o1).equals(extractChars(o2))) {
        return o1.compareTo(o2);
    } else
        return extractInt(o1) - extractInt(o2);
}

@Override
public int compare(Code a, Code b) {

    return isThereAnyNumber(a.getPrimaryCode(), b.getPrimaryCode()) 
            ? isNumber(a.getPrimaryCode()) ? 1 : -1 
                : compareStrings(a.getPrimaryCode(), b.getPrimaryCode());
                }
            });

で借りてるコードを見ついStackoverflowプラスにインポートの自れているかをいかなければならない。

ように順にオブジェ、コンパレータなどの重複を除去、負トがあったのを採用した初めて書は私のオブジェクトはTreeMapの前に書き込むことは、Treeset.で影響が出る場合がありますの性能を少しでもこのリストは、最大約80コードすべきでない問題です。

また同様の問題が私の文字列たスペースで区切られたセグメントです。まるでこのように:

public class StringWithNumberComparator implements Comparator<MyClass> {

@Override
public int compare(MyClass o1, MyClass o2) {
    if (o1.getStringToCompare().equals(o2.getStringToCompare())) {
        return 0;
    }
    String[] first = o1.getStringToCompare().split(" ");
    String[] second = o2.getStringToCompare().split(" ");
    if (first.length == second.length) {
        for (int i = 0; i < first.length; i++) {

            int segmentCompare = StringUtils.compare(first[i], second[i]);
            if (StringUtils.isNumeric(first[i]) && StringUtils.isNumeric(second[i])) {

                segmentCompare = NumberUtils.compare(Integer.valueOf(first[i]), Integer.valueOf(second[i]));
                if (0 != segmentCompare) {
                    // return only if uneven numbers in case there are more segments to be checked
                    return segmentCompare;
                }
            }
            if (0 != segmentCompare) {
                return segmentCompare;
            }
        }
    } else {
        return StringUtils.compare(o1.getDenominazione(), o2.getDenominazione());
    }

    return 0;
}

ご覧のとおり利用していApaches StringUtils.compare()およびNumberUtils.compere()が標準です。

お与えにしたい番号を比較して空間のち、その他の番号なので、この正規表現かなくなりますか?

bbb 12 ccc

eee12ddd jpeg2000 eee

だ書くコンパレータのクラスは、実施するべきである自分を比較する方法が比較二つの文字列の文字による文字です。この比較メソッドはチェックだけを扱うアルファベット文字、数字、または混合型(スペースを含む).いる方法を設定したい混合型の行動かした"使いやすさ"にこだわりの前にアルファベット文字以降は、空間に合う。

Linux glibcを提供strverscmp()でもご利用からgnulibのために述します。しかし真の"人間"ソートは他にもたくさんの癖のように"ビートルズの"ソート"としてビートルズの".ありませんのグループに参加"ボタンをこの汎用的な問題です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top