「"任意の文字列" + 数値」という文字列が複数あり、これを昇順に並べ替えたいです。
文字列ソートだと100が2より前に来てしまうため、正規表現とComparatorで実装しようとしました。
しかし、文字列の重複があり得ることになり(例えばABC1が複数出現する)、その場合は連番を付与することになりました。(連番のつけ方については見て連番だとわかればよいのですが、ABC1、ABC1_2、ABC1_3・・・が基本方針となりました)
単純に末尾から数値を取得して比較すればよいと思っていたのが、連番が付与されることになって考え直すことになり、悩んでいます。
例:
ABC1、ABC1_2、ABC2、ABC2_2、ABC10、ABC011と並べたいです。
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/04/03 02:29
回答3件
0
ベストアンサー
こういうところを使っていろいろ試してみましょう。→Regular Expression Test Drive
まず、正規表現のパターン文字列は次のようになります。
".+?(\d+)(?:_(\d+))?"
最初の".+"はおなじみ「任意の文字列」ですが、今回は".+?"としています。理由は後述。
そのあとの"(\d+)"も「1文字以上の数字」でおなじみ。グループ化してインデックスは1番になります。
そのあと、"(?:(\d+))?"としています。"(?:...)"は「グループ化だけ行う括弧」で、グループ化はするが、groupメソッドで使うインデックスにカウントされない性質を持ちます。ここでは"(\d+)"(アンダースコアと数字1文字以上のつながり)をグループとして、その次の"?"(直前が0回か1回を意味する量指定子)の対象にしています。この数字の部分がグループ2になります。
さて、最初の任意の文字列の部分で".+?"とした理由についてですが、最後のグループが関係します。
最後のグループの量指定子を"?"にしたため、最後のグループについては「無くてもいい」扱いになります。
最初を".+"とした場合、「パターンにマッチすることを優先に最長部分とマッチ」するため、最後のグループをないことにし、末尾の数字をグループ1の数字とみなして、それ以外を".+"にマッチ、という形になり、連番に対応できなくなってしまいます。
そこで、パターンにマッチするよう「最短部分」にマッチさせるため、".+?"としています。
長くなりましたが、これを使ってComparatorを作成すると(文字列がこのパターンにマッチすること前提)
こんな感じになるのでは(未検証)
java
1Comparator<String> comparator = new Comparator<>() { 2 Pattern pattern = Pattern.compile(".+?(\\d+)(?:_(\\d+))?"); 3 @Override 4 public int compare(String s1, String s2) { 5 Matcher m1 = pattern.matcher(s1); 6 Matcher m2 = pattern.matcher(s2); 7 if (m1.find() && m2.find()) { 8 int n1 = Integer.parseInt(m1.group(1)); 9 int n2 = Integer.parseInt(m2.group(1)); 10 int x = Integer.compare(n1, n2); 11 if (x == 0) { 12 n1 = m1.group(2).equals("") ? 1 : Integer.parseInt(m1.group(2)); 13 n2 = m2.group(2).equals("") ? 1 : Integer.parseInt(m2.group(2)); 14 x = Integer.compare(n1, n2); 15 } 16 return x; 17 } else { 18 return 0; //どちらかがマッチしなければこの方法での比較はできないので、場合によっては例外スロー 19 } 20 } 21};
投稿2017/04/03 14:04
編集2017/04/03 14:05総合スコア20651
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
数値部分を数字文字列にした上で、数値の最大値に合わせてゼロで桁合わせしてはどうでしょうか。
例えば数値の最大値が999ならば19を "001""009"、10から99を"010"~"099"のようにしてソートする。
いかがでしょうか。
投稿2017/04/03 02:09
総合スコア2425
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/04/03 02:18
2017/04/03 02:25 編集
2017/04/03 02:25
0
単純に、「数字1_数字2」なら数字1に数字2を足して1引いたものを値とし、「_」がなければ末尾の数字を値とすればいいのでは?
追記
単純な加算だと 2_3 が 3 より大きくなる問題がありましたので訂正します。
数字1に重みをつけてから加算しなければなりませんでした。
投稿2017/04/03 02:05
編集2017/04/03 02:28総合スコア28660
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/04/03 02:11 編集
2017/04/03 02:19
2017/04/03 02:28 編集
2017/04/03 02:32
2017/04/03 02:38
2017/04/03 04:59
2017/04/03 06:52
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。