У меня есть string
, который я хочу разделить на две части. Обычно это имя, оператор и значение. Я хотел бы разделить его на имя и значение. Имя может быть любым, значение тоже. У меня есть массив операторов, и моя идея состоит в том, чтобы использовать его в качестве разделителей:
var input = "name>=2";
var separators = new string[]
{
">",
"> = ",
};
var result = input.Split(separators, StringSplitOptions.RemoveEmptyEntries);
Код выше дает результат name
и =2
. Но если я изменю порядок разделителей, то >=
будет первым, вот так:
var separators = new string[]
{
"> = ",
">",
};
Таким образом, я становлюсь хорошим name
и 2
, чего я и пытаюсь достичь. К сожалению, содержать сепараторы в идеальном порядке мне не под силу. Кроме того, моя коллекция разделителей не является неизменной. Итак, я думаю, может быть, я мог бы разделить string
с более длинными разделителями, имеющими приоритет над более короткими?
Спасибо за помощь!
Здесь — связанный вопрос, объясняющий, почему такое поведение происходит в методе Split()
.
var result = input.Split(separators.OrderByDescending(s => s.Length).ToArray(), StringSplitOptions.RemoveEmptyEntries);
- правильно расставляем разделители Сортировать, а потом разбиваем на некоторые из них
Вы можете попробовать разделить регулярное выражение на чередование, которое сначала перечисляет более длинные >=
:
var input = "name>=2";
string[] parts = Regex.Split(input, "(?:>=|>)");
foreach(var item in res)
{
Console.WriteLine(item.ToString());
}
Это печатает:
name
2
Обратите внимание, что если бы мы разделились на (?:>|>=)
, на выходе были бы name
и =2
.
Возможно, стоит указать, что OP может сгенерировать этот шаблон, используя свой массив separators
и немного действий OrderByDescending
и String.Join
.
@Jamiec Хотел бы я больше знать C#, и в этом случае я мог бы также предложить эти варианты :-)
var pattern = "(?:" + String.Join("|",separators.OrderByDescending(s => s.Length)) + ")"
(например: rextester.com/INYGH99691)
Спасибо за ответ @Tim и jamiec за ценный комментарий. У меня есть доступ к коллекции операторов, но я не могу быть на 100% уверенным, как будут выглядеть операторы, потому что разрешаю добавлять операторы в кастомизации. Из-за этого я бы использовал Regex как абсолютную завершенность. Коллекция операторов может быть расширена, поэтому я предпочитаю более перспективное и менее рискованное решение. Может быть, мне следует написать больше о причинах, по которым коллекция операторов не является неизменной, извините за это. В любом случае, еще раз спасибо за ответ, я уверен, что кто-то с похожей проблемой найдет здесь решение благодаря вам.
Вы можете попробовать несколько вариантов. Если у вас есть коллекция разделителей, вы можете отсортировать их в правильном порядке перед разделением:
using System.Linq;
...
var result = input.Split(
separators.OrderByDescending(item => item.Length), // longest first
StringSplitOptions.RemoveEmptyEntries);
Вы можете попробовать организовать разделители все (включая возможные) в один шаблон, например.
[><=]+
здесь мы разделяем последовательность самый длинный из >
, <
и =
var result = Regex.Split(input, "[><=]+");
Демо:
using System.Text.RegularExpressions;
...
string[] tests = new string[] {
"name>123",
"name<4",
"name=78",
"name==other",
"name===other",
"name<>78",
"name<<=4",
"name=>name + 455",
"name>=456",
"a_b_c=d_e_f",
};
string report = string.Join(Environment.NewLine, tests
.Select(test => string.Join("; ", Regex.Split(test, "[><=]+"))));
Console.Write(report);
Исход:
name; 123
name; 4
name; 78
name; other
name; other
name; 78
name; 4
name; name + 455
name; 456
a_b_c; d_e_f
Спасибо за ответ @Dmitry. Сортировка операторов кажется хорошей идеей. Хотя во втором решении я заметил серьезный недостаток. Если имя будет содержать знак подчеркивания, например. first_name
и коллекция разделителей будет содержать любой разделитель, который также использует подчеркивание, например. _=
, то first_name
тоже будет разбит на first
и name
, что не совсем тот результат, который мне нужен.
@Prolog: да, при организации всех разделителей в единый шаблон в общем случае мы не можем просто механически склеить их вместе. В случае с разделителем _=
мы хотим добавить _=
, мы можем попробовать, скажем, шаблон _?[><=]+
: не более одного _
, за которым следует хотя бы один из символов >
, '<', =
. Значит _=
разделитель, когда _
- нет
var result = Regex.Split(input, "[><=]+");
- мы разделяем любую комбинацию<
,>
и=
, например.name>>4
,name===other
,input<>-456
,name<=5
,name>=7