Как разделить строку с более длинными разделителями, предпочитаемыми более коротким?

У меня есть 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 = Regex.Split(input, "[><=]+"); - мы разделяем любую комбинацию <, > и =, например. name>>4, name===other, input<>-456, name<=5, name>=7
Dmitry Bychenko 10.06.2019 15:37
var result = input.Split(separators.OrderByDescending(s => s.Length).ToArray(), StringSplitOptions.RemoveEmptyEntries); - правильно расставляем разделители Сортировать, а потом разбиваем на некоторые из них
Dmitry Bychenko 10.06.2019 15:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете попробовать разделить регулярное выражение на чередование, которое сначала перечисляет более длинные >=:

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 10.06.2019 15:42

@Jamiec Хотел бы я больше знать C#, и в этом случае я мог бы также предложить эти варианты :-)

Tim Biegeleisen 10.06.2019 15:43
var pattern = "(?:" + String.Join("|",separators.OrderByDescending(s => s.Length)) + ")" (например: rextester.com/INYGH99691)
Jamiec 10.06.2019 15:49

Спасибо за ответ @Tim и jamiec за ценный комментарий. У меня есть доступ к коллекции операторов, но я не могу быть на 100% уверенным, как будут выглядеть операторы, потому что разрешаю добавлять операторы в кастомизации. Из-за этого я бы использовал Regex как абсолютную завершенность. Коллекция операторов может быть расширена, поэтому я предпочитаю более перспективное и менее рискованное решение. Может быть, мне следует написать больше о причинах, по которым коллекция операторов не является неизменной, извините за это. В любом случае, еще раз спасибо за ответ, я уверен, что кто-то с похожей проблемой найдет здесь решение благодаря вам.

Prolog 10.06.2019 16:46
Ответ принят как подходящий

Вы можете попробовать несколько вариантов. Если у вас есть коллекция разделителей, вы можете отсортировать их в правильном порядке перед разделением:

  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 10.06.2019 16:15

@Prolog: да, при организации всех разделителей в единый шаблон в общем случае мы не можем просто механически склеить их вместе. В случае с разделителем _= мы хотим добавить _=, мы можем попробовать, скажем, шаблон _?[><=]+: не более одного _, за которым следует хотя бы один из символов >, '<', =. Значит _= разделитель, когда _ - нет

Dmitry Bychenko 10.06.2019 16:22

Другие вопросы по теме