C #: разбить строку и присвоить результат нескольким строковым переменным - PullRequest
12 голосов
/ 11 марта 2011

У меня есть строка с несколькими полями, разделенными определенным символом, что-то вроде этого:

A, B, C

Я хочу разбить строку назапятые и присвойте каждому результирующему полю свою строковую переменную.В Perl я могу сделать это элегантно так:

my ($varA, $varB, $varC) = split (/,/, $string);

Какой самый простой и элегантный способ достичь того же результата в C #?

Я знаю, чтоЯ могу разбить на массив:

string[] results = string.Split(',');

Но тогда мне придется обращаться к полям через их индекс, например, результаты [2].Это трудно читать и подвержено ошибкам - подумайте об отсутствии 3 полей 30 полей.По этой причине я предпочитаю иметь каждое значение поля в своей именованной переменной.

Ответы [ 8 ]

8 голосов
/ 11 марта 2011

Я согласен. Сокрытие разделения в классе Адаптера кажется хорошим подходом и довольно хорошо передает ваше намерение:

public class MySplitter
{
     public MySplitter(string split)
     {
         var results = string.Split(',');
         NamedPartA = results[0];
         NamedpartB = results[1];
     }

     public string NamedPartA { get; private set; }
     public string NamedPartB { get; private set; }
}
7 голосов
/ 11 марта 2011

Вы можете использовать кортежи (добавлено в .Net 4). Кортежи в MSDN

Это:

public class MySplitter
{
     public MySplitter(string split)
     {
         var results = split.Split(',');
         NamedPartA = results[0];
         NamedpartB = results[1];
     }

     public string NamedPartA { get; private set; }
     public string NamedPartB { get; private set; }
}

Может быть достигнуто с помощью чего-то вроде этого:

public Tuple<string,string> SplitIntoVars(string toSplit)
{
   string[] split = toSplit.Split(',');
   return Tuple.Create(split[0],split[1]);
}

С кортежем вы можете использовать:

var x = SplitIntoVars(arr);
// you can access the items like this:    x.Item1 or x.Item2 (and x.Item3 etc.)

Вы также можете создать кортеж для использования Tuple<string,int> и т. Д.

Также ... Мне не нравятся параметры, поэтому вы эмулируете возвращение нескольких значений с помощью кортежа(и, очевидно, также разных типов).this:

public void SplitIntoVariables(string input, out a, out b, out c)
{
    string pieces[] = input.Split(',');
    a = pieces[0];
    b = pieces[1];
    c = pieces[2];
}

превращается в это:

public Tuple<string,string,string> SplitIntoVariables(string[] input)
    {
        string pieces[] = input.Split(',');
        return Tuple.Create(pieces[0],pieces[1],pieces[2]);
    }

Другими (более изобретательными) параметрами может быть создание ExpandoObject (динамического), который содержит ваши значения (что-то похожее на ViewBag в ASP).NET MVC)

3 голосов
/ 11 марта 2011

А кто не может устоять перед безумием Линка!

string names = "Joe,Bob,Lucy";
var myVars = names.Split(',').Select((x, index) => Tuple.Create(index,x)).ToDictionary(x => "var" + x.Item1, y => y.Item2);
Debug.WriteLine(myVars["var0"]);
2 голосов
/ 01 июля 2015

Не решение одной строки.Но как насчет метода расширения с дополнительным параметром out?

public static IEnumerable<T> Unpack<T>(this IEnumerable<T> source, out T target)
{
    target = source.First();
    return source.Skip(1);
}

Затем вы можете использовать этот метод следующим образом.

string values = "aaa,bbb,ccc";
string x, y, z;
values.Split(',')
    .Unpack(out x)
    .Unpack(out y)
    .Unpack(out z);

Обратите внимание, что метод Unpackперечисляет последовательность дважды.Поэтому я бы использовал его только в том случае, если данные в объекте IEnumerable повторяемы.

Мне было все равно проверить производительность метода, потому что я думал, что обычно мы не распаковываем большой массив.

Конечно, вы можете использовать модификатор ref вместо out, и использование будет другим.

1 голос
/ 07 июня 2017

@ pnvn имеет отличную идею с шаблоном Unpack, но его можно было бы улучшить, чтобы перебирать перечисление за один проход, обеспечивать значения по умолчанию после окончания перечислимого и работать с любым типом или размером перечислимым образом предсказуемым образом. .

Вот пример использования функции C # 7 out variables .

"A,B,C".Split(',')
    .Unpack(out string varA)
    .Unpack(out string varB);

Для этого требуется два метода расширения: один для запуска IEnumerable, второй - для IEnumerator для каждого последующего вызова.

public static IEnumerator<T> Unpack<T>(this IEnumerable<T> source, out T item)
{
    var enumerator = source.GetEnumerator();
    if (enumerator.MoveNext())
    {
        item = enumerator.Current;
        return enumerator;
    }
    item = default(T);
    return null;
}

public static IEnumerator<T> Unpack<T>(this IEnumerator<T> enumerator, out T item)
{
    if (enumerator != null && enumerator.MoveNext())
    {
        item = enumerator.Current;
        return enumerator;
    }            
    item = default(T);
    return null;
}
1 голос
/ 11 марта 2011

Я рекомендую словарь.

List<string> names = new List<string> (){"varA","varB","varC"};
Dictionary<string, string> map = new Dictionary<string, string>();
string[] results = myLongString.Split(',');
for (int i = 0; i < results.Length; i++) map.Add(names[i], results[i]); 
0 голосов
/ 04 августа 2015

Я не мог удержаться от добавления к нелепости :) Пожалуйста, не используйте это "решение", по крайней мере, не как есть.

static class StringExtensions
{
   private static readonly Func<object, string, Action<object, object>> GetSetter =
       (o1, n) => (o2, v) => o1.GetType().GetProperty(n).SetValue(o2, v, null);

   public static T AssignFromCSV<T>(this string csv, T obj, string[] propertyNames)
   {
       var a = csv.Split(new[] {','});
       for (var i = 0 ; i < propertyNames.Length; i++)
       {
           GetSetter(obj, propertyNames[i])(obj, a[i]);
       }
       return obj ;
   }
}

class TargetClass
{
   public string A { get; set; }

   public string B { get; set; }

   public string C { get; set; }
}

Использование:

var target = "1,2,3".AssignFromCSV(new TargetClass(), new[] {"A", "B", "C"}) ;
0 голосов
/ 11 марта 2011

В C # нет встроенного способа выполнять множественные присваивания, как в Perl;однако существует несколько решений для передачи данных в каждую переменную по обычному пути.

...