Создайте псевдоним для gcc с вашим любимым включением.
alias mygcc='gcc -I /whatever/'
Это потому, что упорядочение по умолчанию для строки является стандартным буквенно-цифровым словарным (лексикографическим) заказом, а ABC11 будет предшествовать ABC2, потому что упорядочение всегда происходит слева направо.
Чтобы получить то, что вы хотите, вы нужно поместить числовую часть в вашем предложении order, что-то вроде:
var result = partNumbers.OrderBy(x => PadNumbers(x));
, где PadNumbers
может быть определено как:
public static string PadNumbers(string input)
{
return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}
. Эти колодки нумеруют для любого числа (или числа), которые появляются во входной строке, так что OrderBy
видит:
ABC0000000010
ABC0000000001
...
AB0000000011
Заполнение происходит только на клавише, используемом для сравнения. Исходные строки (без заполнения) сохраняются в результате.
Обратите внимание, что этот подход предполагает максимальное количество цифр для чисел на входе.
Вы можете использовать PInvoke для получения быстрого и хорошего результата:
class AlphanumericComparer : IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
static extern int StrCmpLogicalW(string s1, string s2);
public int Compare(string x, string y) => StrCmpLogicalW(x, y);
}
Вы можете использовать его как AlphanumComparatorFast
из вышеприведенного ответа.
Нет естественного способа сделать это в .NET, , но посмотрите на это сообщение в блоге по естественной сортировке
. Вы можете поместить это в метод расширения и использовать это вместо OrderBy
Вы можете PInvoke на StrCmpLogicalW
(функция windows) сделать это. См. Здесь: Природный порядок сортировки в C #
Если вы хотите отсортировать список объектов по определенному свойству с помощью LINQ и пользовательского сопоставителя, такого как Dave Koelle , вы сделали бы что-то вроде этого:
...
items = items.OrderBy(x => x.property, new AlphanumComparator()).ToList();
...
Вам также нужно изменить класс Dave для наследования с System.Collections.Generic.IComparer<object>
вместо базового IComparer
, чтобы подпись класса стала:
...
public class AlphanumComparator : System.Collections.Generic.IComparer<object>
{
...
Лично я предпочитаю реализацию Джеймс Маккормак , поскольку он реализует IDisposable, хотя мой бенчмаркинг показывает, что он немного медленнее.
Я не знаю, как это сделать в LINQ, но, возможно, вам это нравится:
Array.Sort(partNumbers, new AlphanumComparatorFast());
// Показывать результаты
foreach (string h in partNumbers )
{
Console.WriteLine(h);
}
Правильная реализация алфавитно-цифрового метода сортировки, который «работает просто», можно найти на сайте Dave Koelle . Версия C # здесь .
public class AlphanumComparatorFast : IComparer
{
List<string> GetList(string s1)
{
List<string> SB1 = new List<string>();
string st1, st2, st3;
st1 = "";
bool flag = char.IsDigit(s1[0]);
foreach (char c in s1)
{
if (flag != char.IsDigit(c) || c=='\'')
{
if(st1!="")
SB1.Add(st1);
st1 = "";
flag = char.IsDigit(c);
}
if (char.IsDigit(c))
{
st1 += c;
}
if (char.IsLetter(c))
{
st1 += c;
}
}
SB1.Add(st1);
return SB1;
}
public int Compare(object x, object y)
{
string s1 = x as string;
if (s1 == null)
{
return 0;
}
string s2 = y as string;
if (s2 == null)
{
return 0;
}
if (s1 == s2)
{
return 0;
}
int len1 = s1.Length;
int len2 = s2.Length;
int marker1 = 0;
int marker2 = 0;
// Walk through two the strings with two markers.
List<string> str1 = GetList(s1);
List<string> str2 = GetList(s2);
while (str1.Count != str2.Count)
{
if (str1.Count < str2.Count)
{
str1.Add("");
}
else
{
str2.Add("");
}
}
int x1 = 0; int res = 0; int x2 = 0; string y2 = "";
bool status = false;
string y1 = ""; bool s1Status = false; bool s2Status = false;
//s1status ==false then string ele int;
//s2status ==false then string ele int;
int result = 0;
for (int i = 0; i < str1.Count && i < str2.Count; i++)
{
status = int.TryParse(str1[i].ToString(), out res);
if (res == 0)
{
y1 = str1[i].ToString();
s1Status = false;
}
else
{
x1 = Convert.ToInt32(str1[i].ToString());
s1Status = true;
}
status = int.TryParse(str2[i].ToString(), out res);
if (res == 0)
{
y2 = str2[i].ToString();
s2Status = false;
}
else
{
x2 = Convert.ToInt32(str2[i].ToString());
s2Status = true;
}
//checking --the data comparision
if(!s2Status && !s1Status ) //both are strings
{
result = str1[i].CompareTo(str2[i]);
}
else if (s2Status && s1Status) //both are intergers
{
if (x1 == x2)
{
if (str1[i].ToString().Length < str2[i].ToString().Length)
{
result = 1;
}
else if (str1[i].ToString().Length > str2[i].ToString().Length)
result = -1;
else
result = 0;
}
else
{
int st1ZeroCount=str1[i].ToString().Trim().Length- str1[i].ToString().TrimStart(new char[]{'0'}).Length;
int st2ZeroCount = str2[i].ToString().Trim().Length - str2[i].ToString().TrimStart(new char[] { '0' }).Length;
if (st1ZeroCount > st2ZeroCount)
result = -1;
else if (st1ZeroCount < st2ZeroCount)
result = 1;
else
result = x1.CompareTo(x2);
}
}
else
{
result = str1[i].CompareTo(str2[i]);
}
if (result == 0)
{
continue;
}
else
break;
}
return result;
}
}
ИСПОЛЬЗОВАНИЕ этого класса:
List<string> marks = new List<string>();
marks.Add("M'00Z1");
marks.Add("M'0A27");
marks.Add("M'00Z0");
marks.Add("0000A27");
marks.Add("100Z0");
string[] Markings = marks.ToArray();
Array.Sort(Markings, new AlphanumComparatorFast());
Хорошо выглядит, что он делает лексикографическое упорядочение независимо от мелких или больших символов.
Вы можете попробовать использовать какое-то пользовательское выражение в этой лямбде, чтобы это сделать.
Поскольку число символов в начале является переменной, регулярное выражение помогло бы:
var re = new Regex(@"\d+$"); // finds the consecutive digits at the end of the string
var result = partNumbers.OrderBy(x => int.Parse(re.Match(x).Value));
Если было фиксированное количество символов префикса, то вы могли бы использовать метод Substring
для извлечение, начиная с соответствующих символов:
// parses the string as a number starting from the 5th character
var result = partNumbers.OrderBy(x => int.Parse(x.Substring(4)));
Если числа могут содержать разделитель десятичных чисел или разделитель тысяч, то регулярное выражение должно также допускать эти символы:
var re = new Regex(@"[\d,]*\.?\d+$");
var result = partNumbers.OrderBy(x => double.Parse(x.Substring(4)));
Если строка, возвращаемая регулярным выражением или Substring
, может быть недоступна с помощью int.Parse
/ double.Parse
, используйте соответствующий вариант TryParse
:
var re = new Regex(@"\d+$"); // finds the consecutive digits at the end of the string
var result = partNumbers.OrderBy(x => {
int? parsed = null;
if (int.TryParse(re.Match(x).Value, out var temp)) {
parsed = temp;
}
return parsed;
});