С# Regex.Split: удаление пустых результатов
Я работаю над приложением, которое импортирует тысячи строк, где каждая строка имеет такой формат:
|* 9070183020 |04.02.2011 |107222 |M/S SUNNY MEDICOS |GHAZIABAD | 32,768.00 |
Я использую следующий Regex
, чтобы разделить строки на нужные мне данные:
Regex lineSplitter = new Regex(@"(?:^\|\*|\|)\s*(.*?)\s+(?=\|)");
string[] columns = lineSplitter.Split(data);
foreach (string c in columns)
Console.Write("[" + c + "] ");
Это дает мне следующий результат:
[] [9070183020] [] [04.02.2011] [] [107222] [] [M/S SUNNY MEDICOS] [] [GHAZIABAD] [] [32,768.00] [|]
Теперь у меня есть два вопроса.
1. Как удалить пустые результаты. Я знаю, что могу использовать:
string[] columns = lineSplitter.Split(data).Where(s => !string.IsNullOrEmpty(s)).ToArray();
но есть ли встроенный метод для удаления пустых результатов?
2. Как удалить последний канал?
Спасибо за любую помощь.
С Уважением,
Yogesh.
РЕДАКТИРОВАТЬ:
Я думаю, что мой вопрос был немного непонят. Я никогда не думал о том, как я могу это сделать. Речь шла только о том, как я могу это сделать, изменив Regex
в приведенном выше коде.
Я знаю, что могу сделать это разными способами. Я уже сделал это с указанным выше кодом с предложением Where
и с альтернативным способом, который также (более двух раз) быстрее:
Regex regex = new Regex(@"(^\|\*\s*)|(\s*\|\s*)");
data = regex.Replace(data, "|");
string[] columns = data.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
Во-вторых, в качестве тестового примера моя система может анализировать 92k + таких строк менее чем за 1,5 секунды в исходном методе и менее чем за 700 миллисекунд во втором методе, где я никогда не найду более двух тысяч в реальном времени поэтому я не думаю, что мне нужно подумать о скорости здесь. На мой взгляд, думать о скорости в этом случае - преждевременная оптимизация.
Я нашел ответ на свой первый вопрос: его нельзя сделать с помощью Split
, поскольку такой опции не существует.
Ищем ответ на мой второй вопрос.
Ответы
Ответ 1
Regex lineSplitter = new Regex(@"[\s*\*]*\|[\s*\*]*");
var columns = lineSplitter.Split(data).Where(s => s != String.Empty);
или вы можете просто сделать:
string[] columns = data.Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries);
foreach (string c in columns) this.textBox1.Text += "[" + c.Trim(' ', '*') + "] " + "\r\n";
И нет, нет возможности удалить пустые записи для RegEx.Split, как и для String.Split.
Вы также можете использовать совпадения.
Ответ 2
Я думаю, что это может работать как эквивалент удаления пустых строк:
string[] splitter = Regex.Split(textvalue,@"\s").Where(s => s != String.Empty).ToArray<string>();
Ответ 3
В качестве альтернативы расщеплению, которое всегда будет вызывать проблемы, когда ваши разделители также присутствуют в начале и в конце ввода, вы можете попробовать совместить содержимое внутри труб:
foreach (var token in Regex.Matches(input, @"\|\*?\s*(\S[^|]*?)\s*(?=\|)"))
{
Console.WriteLine("[{0}]", token.Groups[1].Value);
}
// Prints the following:
// [9070183020]
// [04.02.2011]
// [107222]
// [M/S SUNNY MEDICOS]
// [GHAZIABAD]
// [32,768.00]
Ответ 4
Как насчет этого:
при условии, что у нас есть строка:
line1="|* 9070183020 |04.02.2011 |107222 |M/S SUNNY MEDICOS |GHAZIABAD | 32,768.00 |";
мы можем получить требуемый результат:
string[] columns =Regex.Split(line1,"|");
foreach (string c in columns)
c=c.Replace("*","").Trim();
Это даст следующий результат:
[9070183020] [04.02.2011] [107222] [M/S SUNNY MEDICOS] [GHAZIABAD] [32,768.00]
Ответ 5
У меня может быть неправильная идея здесь, но вы просто хотите разбить строку data
, используя '|' символ как разделитель? В этом случае вы можете:
string[] result = data.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).ToArray();
Это вернет все поля без пробелов и с пустыми полями. Вы можете использовать то, что вам нравится в части Select
, чтобы отформатировать результаты, например.
.Select(d => "[" + d.Trim() + "]").ToArray();
Ответ 6
Не используйте регулярное выражение в вашем случае.
Кажется, вам это не нужно, и регулярные выражения намного медленнее (и имеют гораздо более высокие издержки), чем напрямую, используя строковые функции.
Поэтому используйте несколько:
const Char[] splitChars = new Char[] {'|'};
string[] splitData = data.Split(splitChars, StringSplitOptions.RemoveEmptyEntries)
Ответ 7
Основываясь на @Jaroslav Jandek отличный ответ, я написал extension method
, я сказал, что здесь, может быть, это может сэкономить ваше время.
/// <summary>
/// String.Split with RemoveEmptyEntries option for clean up empty entries from result
/// </summary>
/// <param name="s">Value to parse</param>
/// <param name="separator">The separator</param>
/// <param name="index">Hint: pass -1 to get Last item</param>
/// <param name="wholeResult">Get array of split value</param>
/// <returns></returns>
public static object CleanSplit(this string s, char separator, int index, bool wholeResult = false)
{
if (string.IsNullOrWhiteSpace(s)) return "";
var split = s.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries);
if (wholeResult) return split;
if (index == -1) return split.Last();
if (split[index] != null) return split[index];
return "";
}
Ответ 8
1. Как удалить пустые результаты?
Вы можете использовать LINQ, чтобы удалить все записи, равные string.Empty:
string[] columns = lineSplitter.Split(data);
columns = columns.ToList().RemoveAll(c => c.Equals(string.Empty)).ToArray();
2. Как удалить последний канал?
Здесь вы можете использовать LINQ, чтобы удалить все записи, равные символу, который вы хотите удалить:
columns = columns.ToList().RemoveAll(c => c.Equals("|")).ToArray();
Ответ 9
используйте это решение:
string stringwithDelemeterNoEmptyValues= string.Join(",", stringwithDelemeterWithEmptyValues.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));