我正在尝试编写一个 C# 程序,对字母数字字符串列表进行排序并将连续的数值组合到范围中。
我会有一个字符串列表 例如。
“0P228PBC”、“0P229PBC”、“0P230PBC”。
它们需要合并到
0P228PBC~0P230PBC
但如果它们之间的差值仅为 1,则不需要波浪符号。 例如。
前
“0P228PBC”、“0P229PBC”。
它们需要合并到
“0P228PBC”、“0P229PBC”。
另一种可能是
“AB999B”、“AC000B”、“AC001B”
然后它们应该合并到
AB999B~AC001B
因为999+2变成了AB->AC
例如,给定列表:
"0n7asd1112", "0n7asd1113", "0N7P1ABC", "0N7P2ABC", "0N7P3ABC", "0P228PBC", "0P229PBC", "0P230PBC", "62700001", "62700002", "627000010", "ab51561aa", "ab51561ab", "ab51561ac","AB999B","AC000B","AC001B"
我想得到的输出为:
"0n7asd1112","0n7asd1113", "0N7P1ABC~0N7P3ABC", "0P228PBC~0P230PBC", "62700001","62700002", "627000010", "ab51561aa~ab51561ac","AB999B~AC001B"
我在实现所需输出方面面临问题,特别是在将连续值正确组合到范围中时。
任何人都可以提供指导、建议或更好的方法来实现这一目标吗?
提前非常感谢!
我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace SortTest
{
internal class Program
{
public static int AlphanumericCompare(string a, string b)
{
var regex = new Regex("([0-9]+)|([a-zA-Z]+)");
var matchesA = regex.Matches(a);
var matchesB = regex.Matches(b);
int i = 0;
while (i < matchesA.Count && i < matchesB.Count)
{
var matchA = matchesA[i];
var matchB = matchesB[i];
if (matchA.Value.All(char.IsDigit) && matchB.Value.All(char.IsDigit))
{
var numA = int.Parse(matchA.Value);
var numB = int.Parse(matchB.Value);
if (numA != numB)
return numA.CompareTo(numB);
}
else
{
var strCompare = string.Compare(matchA.Value, matchB.Value, StringComparison.OrdinalIgnoreCase);
if (strCompare != 0)
return strCompare;
}
i++;
}
if (i < matchesA.Count) return 1;
if (i < matchesB.Count) return -1;
return 0;
}
public static string GenerateRange(IEnumerable<string> sortedList)
{
List<string> output = new List<string>();
string start = null;
string end = null;
foreach (var s in sortedList)
{
if (start == null)
{
start = s;
end = s;
continue;
}
if (AlphanumericCompare(Increment(end), s) == 0)
{
end = s;
}
else
{
output.Add(start == end ? start : $"{start}~{end}");
start = s;
end = s;
}
}
// Handle the last range
output.Add(start == end ? start : $"{start}~{end}");
return string.Join(" ", output);
}
public static string Increment(string input)
{
var regex = new Regex("([0-9]+)$");
var match = regex.Match(input);
if (match.Success)
{
var num = int.Parse(match.Value) + 1;
return regex.Replace(input, num.ToString());
}
else
{
return input + "1";
}
}
static void Main(string[] args)
{
var items = new List<string>
{
"0n7asd1112", "0n7asd1113", "0N7P1ABC", "0N7P2ABC", "0N7P3ABC",
"0P228PBC", "0P229PBC", "0P230PBC", "62700001", "62700002",
"627000010", "ab51561aa", "ab51561ab", "ab51561ac","AB999B","AC000B","AC001B"
};
var sortedItems = items.OrderBy(x => x, Comparer<string>.Create(AlphanumericCompare));
var result = GenerateRange(sortedItems);
Console.WriteLine(result);
}
}
}
运行输出:
"0n7asd1112~0n7asd1113 0N7P1ABC 0N7P2ABC 0N7P3ABC 0P228PBC 0P229PBC 0P230PBC 62700001~62700002 627000010 AB999B ab51561aa ab51561ab ab51561ac AC000B AC001B"
您可以这样对它们进行排序:
public static async Task Main()
{
var inputs = new[]
{
"0n7asd1112", "0n7asd1113", "0N7P1ABC", "0N7P2ABC", "0N7P3ABC", "0P228PBC", "0P229PBC", "0P230PBC",
"62700001", "62700002", "627000010", "ab51561aa", "ab51561ab", "ab51561ac", "AB999B", "AC000B", "AC001B"
};
foreach (var a in inputs.Select(x => new SplitDto(x)).OrderBy(x => x))
{
Console.WriteLine(a.Original);
}
}
public sealed class SplitDto : IComparable<SplitDto>
{
private readonly string _input;
private readonly List<IComparable> _forCompare;
public SplitDto(string input)
{
_input = input;
_forCompare = Regex.Matches(input, "(?<Alpha>[a-zA-Z]+)|(?<Numeric>[0-9]+)")
.Where(x=> !string.IsNullOrWhiteSpace(x.Value))
.Select(x => x.Groups["Alpha"].Success ? (IComparable)x.Value : long.Parse(x.Value)).ToList();
}
public int CompareTo(SplitDto other)
{
if (ReferenceEquals(this, other)) return 0;
if (ReferenceEquals(null, other)) return 1;
var cmp = _forCompare.Count.CompareTo(_forCompare.Count);
if (cmp != 0)
return cmp;
for (int i = 0; i < _forCompare.Count; i++)
{
if (_forCompare[i].GetType() != other._forCompare[i].GetType())
{
cmp = _forCompare[i].ToString().CompareTo(other._forCompare[i].ToString());
if (cmp != 0)
return cmp;
}
else
{
cmp = _forCompare[i].CompareTo(other._forCompare[i]);
if (cmp != 0)
return cmp;
}
}
return 0;
}
public int CompareTo(object obj)
{
if (ReferenceEquals(null, obj)) return 1;
if (ReferenceEquals(this, obj)) return 0;
return obj is SplitDto other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(SplitDto)}");
}
}
输出:
0n7asd1112
0n7asd1113
0N7P1ABC
0N7P2ABC
0N7P3ABC
0P228PBC
0P229PBC
0P230PBC
62700001
62700002
627000010
ab51561aa
ab51561ab
ab51561ac
AB999B
AC000B
AC001B
分组我稍后会发布。