Сортировка строк с числами и символами
Есть массив строк
List<string> s = new List<string>{"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15c","15b","150","15a"};
Если мы просто вызываем
s.Sort();
То он сортирует их как 1 10 11 12 13 14 150 15a 15b 15c 2 3 4 5 6 7 8 9
Как сделать чтобы он выдавал интуитивно человеческую сортировку? Т.е. работала и сортировка по string, но в первую очередь - еще и по значению числа. Т.е. правильный вывод в данном случае будет
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15a,15b,15c,150;
Я понимаю, что можно написать компаратор, который, вероятно, ищет цифры внутри строки, если находит их, проверяет, где больше, а если строку - то по алфавиту, но как это конкретно реализовать?
И тут скорее вопрос, может быть что-то подобное уже реализовано? Может есть какой нибудь StringComparsion.NumericFirst, который просто аргументом в сортировку передается и сортирует так, как рассортировал бы это человек?
Ответы (1 шт):
Вот моя попытка. На гениальность не претендую, потому что сам в регулярках слабоват, возможно есть способ проще.
public static void Main()
{
List<string> s = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15c", "15b", "150", "15a" };
s.Sort(new MyComparer());
Console.WriteLine(string.Join(", ", s));
Console.ReadKey();
}
public class MyComparer : IComparer<string>
{
private readonly Regex regex = new Regex(@"(\d+)([a-z]?)");
public int Compare(string x, string y)
{
Match m1 = regex.Match(x);
Match m2 = regex.Match(y);
int a = int.Parse(m1.Groups[1].Value);
int b = int.Parse(m2.Groups[1].Value);
if (a < b)
return -1;
if (a > b)
return 1;
return string.Compare(m1.Groups[2].Value, m2.Groups[2].Value);
}
}
Опять же, здесь нет никакого защитного программирования, если будете использовать этот вариант, позаботьтесь о случаях, когда строка имеет неправильный формат.
Вывод в консоль
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15a, 15b, 15c, 150
Вариант без int.Parse.
public class MyComparer : IComparer<string>
{
private readonly Regex regex = new Regex(@"(\d+)([a-z]?)");
public int Compare(string x, string y)
{
Match m1 = regex.Match(x);
Match m2 = regex.Match(y);
string num1 = m1.Groups[1].Value;
string num2 = m2.Groups[1].Value;
if (num1.Length < num2.Length)
return -1;
if (num1.Length > num2.Length)
return 1;
int cmp = string.Compare(num1, num2);
if (cmp != 0)
return cmp;
return string.Compare(m1.Groups[2].Value, m2.Groups[2].Value);
}
}