简体   繁体   English

对包含数字的字符串数组进行排序

[英]Sorting array of strings that contain number

I'm implementing some code for my college and I have to sort two classes by its name.我正在为我的大学实现一些代码,我必须按其名称对两个类进行排序。 So, I started using Java's compareTo for Strings, but it wasn't doing it correctly.所以,我开始使用 Java 的compareTo处理字符串,但它没有正确执行。 For example, I have these two names TEST-6 and TEST-10 .例如,我有这两个名称TEST-6TEST-10 But, the result was TEST-10 ahead of TEST-6 .但是,结果是TEST-10领先于TEST-6

I've searched and got this solution:我已经搜索并得到了这个解决方案:

private int compare(String o1, String o2) {
    return extractInt(o1) - extractInt(o2);
}
private int extractInt(String s) {
    String num = s.replaceAll("\\D", "");
    // return 0 if no digits found
    return num.isEmpty() ? 0 : Integer.parseInt(num);
}

But my strings could assume any form.但我的弦可以呈现任何形式。 And when I tried this test: TEST-6 and TEST10 ) the result was TEST-6 ahead of TEST10 , but what I expect is TEST10 then TEST-6 .当我尝试这个测试时: TEST-6TEST10 )结果是TEST-6领先于TEST10 ,但我期望的是TEST10然后是TEST-6

The expected result should be normal string comparison, but comparing the full number when it is needed.预期的结果应该是正常的字符串比较,但是在需要的时候比较全数。 So if substrings before numbers are equal, the number is compared, if not, keep string comparison.因此,如果数字之前的子字符串相等,则比较该数字,如果不相等,则继续进行字符串比较。 Or something like this:或者是这样的:

TE
TES-100
TEST-1
TEST-6
TESTT-0
TEXT-2
109

You can do something like that:你可以这样做:

list.sort(Comparator.comparing(YourClass::removeNumbers).thenComparing(YourClass::keepNumbers));

These are two methods:这是两种方法:

private static String removeNumbers(String s) {
    return s.replaceAll("\\d", "");
}

private static Integer keepNumbers(String s) {
    String number = s.replaceAll("\\D", "");
    if (!number.isEmpty()) {
        return Integer.parseInt(number);
    }
    return 0;
}

For following data:对于以下数据:

List<String> list = new ArrayList<>();
list.add("TEXT-2");
list.add("TEST-6");
list.add("TEST-1");
list.add("109");
list.add("TE");
list.add("TESTT-0");
list.add("TES-100");

This is the sorting result:这是排序结果:

[109, TE, TES-100, TEST-1, TEST-6, TESTT-0, TEXT-2]

Here's a compare method that we're using to sort strings that can contain multiple numbers at any location (eg strings like "TEST-10.5" or "TEST-42-Subsection-3" ):这是一个比较方法,我们用于对在任何位置可以包含多个数字的字符串进行排序(例如,像"TEST-10.5""TEST-42-Subsection-3"这样的字符串):

boolean isDigit( char c ) {
  return '0' <= c && c <= '9';
}

int compare( String left, String right, Collator collator ) {
  if ( left == null || right == null ) {
    return left == right ? 0 : ( left == null ? -1 : 1 );
  }

  String s1 = left.trim();
  String s2 = right.trim();

  int l1 = s1.length();
  int l2 = s2.length();
  int i1 = 0;
  int i2 = 0;
  while ( i1 < l1 && i2 < l2 ) {
    boolean isSectionNumeric = isDigit( s1.charAt( i1 ) );
    if ( isSectionNumeric != isDigit( s2.charAt( i2 ) ) ) {
      // one of the strings now enters a digit section and one is in a text section so we're done 
      //switch to -1 : 1 if you want numbers before text
      return isSectionNumeric ? 1 : -1;
    }

    // read next section
    int start1 = i1;
    int start2 = i2;
    for ( ++i1; i1 < l1 && isDigit( s1.charAt( i1 ) ) == isSectionNumeric; ++i1 ){/* no operation */}
    for ( ++i2; i2 < l2 && isDigit( s2.charAt( i2 ) ) == isSectionNumeric; ++i2 ){/* no operation */}
    String section1 = s1.substring( start1, i1 );
    String section2 = s2.substring( start2, i2 );

    // compare the sections:
    int result =
        isSectionNumeric ? Long.valueOf( section1 ).compareTo( Long.valueOf( section2 ) )
      : collator == null ? section1.trim().compareTo( section2.trim() )
      :                    collator.compare( section1.trim(), section2.trim() );

    if ( result != 0 ) {
      return result;
    }

    if ( isSectionNumeric ) {
      // skip whitespace
      for (; i1 < l1 && Character.isWhitespace( s1.charAt( i1 ) ); ++i1 ){/* no operation */}
      for (; i2 < l2 && Character.isWhitespace( s2.charAt( i2 ) ); ++i2 ){/* no operation */}
    }
  }

  // we've reached the end of both strings but they still are equal, so let's do a "normal" comparison
  if ( i1 == l1 && i2 == l2 ) {      
    return collator == null ? left.compareTo( right ) : collator.compare( left, right );
  }

  // we've reached the end of only one string, so the other must either be greater or smaller
  return ( i1 == l1 )? -1 : 1;
}

The idea is to "split" the strings into "text" and numeric sections and to compare the sections one by one.这个想法是将字符串“拆分”为“文本”和数字部分,并逐个比较这些部分。 Decimal numbers would be supported in that the integer, decimal point and fraction parts would be 3 sections that are compared individually.将支持小数,因为 integer、小数点和小数部分将是 3 个单独比较的部分。

This would basically be similar to splitting a string into an array of substring and comparing the elements at each corresponding index.这基本上类似于将字符串拆分为 substring 数组并比较每个相应索引处的元素。 You then have the following situations:然后你有以下情况:

  • both elements are texts: do a normal string comparison两个元素都是文本:进行正常的字符串比较
  • both elements represent numbers: parse and compare the numbers两个元素都代表数字:解析和比较数字
  • one element is a text and the other represents a number: decide which one is greater一个元素是文本,另一个代表数字:决定哪个更大
  • we've reached the end of both strings but all elements are equal: we could be done or do a "normal" comparison on the entire strings to get an order if possible我们已经到达两个字符串的末尾,但所有元素都是相等的:如果可能的话,我们可以完成或对整个字符串进行“正常”比较以获得顺序
  • we've reached the end of only one string and they are still equal: the longer one is reported to be greater (must be because there's more content;) )我们只到达了一个字符串的末尾,它们仍然相等:据报道,越长的字符串越大(一定是因为内容更多;))

Note that this is just our way of doing it and there are others as well (eg ones that don't skip whitespace).请注意,这只是我们这样做的方式,还有其他方式(例如不跳过空格的方式)。

if i am right,the problem is with your character '-',by using string.replace("-","") and then you can proceed with the normal sorting,have the string as it is for sorting,hopefully it should work as you expect.如果我是对的,问题出在你的字符'-'上,通过使用 string.replace("-","") 然后你可以继续正常排序,让字符串按原样进行排序,希望它应该按您的预期工作。

String num = s.replaceAll("\\D", "").replace("-","");

if you won't have any negative values it should work,even then apply the regex for checking is it a negative number or string contains the '-'.如果您没有任何负值,它应该可以工作,即使然后应用正则表达式来检查它是负数还是包含'-'的字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM