У меня есть строковый ввод, который выглядит как var input = "AB-PQ-EF=CD-IJ=XY-JK".
Я хочу знать, есть ли способ использовать метод string.split() в C# и LINQ, чтобы я мог получить массив строк, который выглядит как этот var output = ["AB-PQ", "PQ-EF", "EF=CD", "CD-IJ", "IJ=XY", "XY-JK"]. В настоящее время я делаю то же преобразование вручную, повторяя входную строку.
Я знаю, что разделителей будет только два '-', '='
Но они также присутствуют там, где вам не нужно разбивать строку
Да, именно поэтому я подумал, есть ли способ объединить возможности LINQ с split () для достижения этой цели.
Твоя струна всегда такая? Значение 2 символа, разделителя, 2 символа и т. д.
Вы рассматривали возможность использования регулярных выражений?
@Haytam Нет, разделители фиксированы, но количество окружающих их символов не фиксировано. Это может быть 3 символа, 4 символа и т. д.





Вот рабочий сценарий. Если бы у вас был постоянный фиксированный разделитель, вы бы смотрели только на один вызов Regex.split. Ваша исходная строка не имеет это, но мы можем достаточно легко сделать некоторые дублирования в этом вводе, чтобы строка стала разделяемой.
string input = "ABC-PQ-EF=CD-IJ=XYZ-JK";
string s = Regex.Replace(input, @"((?<=[=-])[A-Z]+(?=[=-]))", "$1~$1");
Console.WriteLine(s);
var items = Regex.Split(s, @"(?<=[A-Z]{2}[=-][A-Z]{2})[~]");
foreach (var item in items)
{
Console.WriteLine(item);
}
ABC-PQ~PQ-EF~EF=CD~CD-IJ~IJ=XYZ~XYZ-JK
ABC-PQ
PQ-EF
EF=CD
CD-IJ
IJ=XYZ
XYZ-JK
Если вы внимательно посмотрите на самую первую строку вывода выше, вы увидите трюк, который я использовал. Я просто соединил нужные пары через другой разделитель (в идеале ~ больше нигде в вашей строке не появляется). Затем нам просто нужно разделить по этому разделителю.
Как сказал OP, количество символов не установлено на 2.
@Haytam Я обобщил свой ответ, чтобы охватить переменное количество символов.
Не не-имеющий-постоянный-фиксированный-разделитель останавливает работу одиночного вызова Regex.Split, он должен дублировать буквы.
@Rawling Я не понимаю ваш комментарий или то, что вы пытаетесь здесь сказать. Если в моем ответе есть изъян, укажите на него.
Протестируйте его со строкой ABC-PQ-EFZ=CD-IJ=XYZ-JK, последний вывод неверен XYZ-J JK
@TimBiegeleisen В вашем примере я ожидаю, что последняя строка в массиве будет «J-JK».
@ pango89 Я исправил. Это непростая задача.
@ Тим, где вы говорите Если бы у вас был постоянный фиксированный разделитель, вы бы смотрели только на один вызов Regex.split, я считаю, что вы ошибаетесь. Даже если бы у вас был только один разделитель, вы все равно не смогли бы Split, так что каждая буква на входе появлялась в двух элементах на выходе. И наоборот, если бы Split действительно работал, он, вероятно, работал бы независимо от количества возможных разделителей.
@Rawling Я думаю, что теперь понимаю, о чем вы говорите. Но если вы читаете мой ответ, я переделываю строку так, чтобы каждая группа является была аккуратно разделена одним фиксированным разделителем. Это было сутью моего (возможно, не оптимального) ответа.
Можете ли вы использовать регулярное выражение вместо разделения?
var input = "AB-PQ-EF=CD-IJ=XY-JK";
var pattern = new Regex(@"(?<![A-Z])(?=([A-Z]+[=-][A-Z]+))");
var output = pattern.Matches(input).Cast<Match>().Select(m => m.Groups[1].Value).ToArray();
Как использовать регулярное выражение, если я также хочу выполнить преобразование output => input?
Для решения, использующего string.Split и LINQ, нам просто нужно отслеживать длину каждой части по мере продвижения, чтобы разделитель можно было извлечь из исходной строки, например:
var input = "ABC-PQ-EF=CDED-IJ=XY-JKLM";
var split = input.Split('-', '=');
int offset = 0;
var result = split
.Take(split.Length - 1)
.Select((part, index) => {
offset += part.Length;
return $"{part}{input[index + offset]}{split[index + 1]}";})
.ToArray();
Вы можете попробовать следующий подход:
Здесь мы разделим строку на основе специальных символов. Затем мы переберем элементы в цикле и будем выбирать до следующей группы символов.
Пример: получить AB и получить значения до PQ
string valentry = "AB-PQ-EF=CD-IJ=XY-JK";
List<string> filt = Regex.Split(valent, @"[\-|\=]").ToList();
var listEle = new List<string>();
fil.ForEach(x =>
{
if (valentry .IndexOf(x) != valentry .Length - 2)
{
string ele = valentry.Substring(valentry .IndexOf(x), 5);
if (!String.IsNullOrEmpty(ele))
listEle.Add(ele);
}
});
Не могли бы вы приспособить что-то подобное? Просто нужно изменить факторизацию.
List<string> lsOut = new List<string>() { };
string sInput = "AB-PQ-EF=CD-IJ=XY-JK";
string sTemp = "";
for (int i = 0; i < sInput.Length; i++)
{
if ( (i + 1) % 6 == 0)
{
continue;
}
// add to temp
sTemp += sInput[i];
// multiple of 5, add all the temp to list
if ( (i + 1 - lsOut.Count) % 5 == 0)
{
lsOut.Add(sTemp);
sTemp = "";
}
if (sInput.Length == i + 1)
{
lsOut.Add(sTemp);
}
}
string input = "AB-PQ-EF=CD-IJ=XY-JK";
var result = new Regex(@"(?<![A-Z])(?=([A-Z]+[=-][A-Z]+))").Matches(input)
.Cast<Match>().Select(m => m.Groups[1].Value).ToArray();
foreach (var item in result)
{
Console.WriteLine(item);
}
Недавно изучал Haskell, поэтому вот рекурсивное решение.
static IEnumerable<string> SplitByPair(string input, char[] delimiter)
{
var sep1 = input.IndexOfAny(delimiter);
if (sep1 == -1)
{
yield break;
}
var sep2 = input.IndexOfAny(delimiter, sep1 + 1);
if (sep2 == -1)
{
yield return input;
}
else
{
yield return input.Substring(0, sep2);
foreach (var other in SplitByPair(input.Substring(sep1 + 1), delimiter))
{
yield return other;
}
}
}
Хорошие вещи
Поскольку в вашей строке нет фиксированного разделителя для разделения, вам необходимо вручную выполнить итерацию и разделить текст