C#:拆分字符串并将结果分配给多个字符串变量

时间:2011-03-10 21:36:18

标签: c# perl string split

我有一个字符串,其中有几个字段由特定字符分隔,如下所示:

  

A,B,C

我想在逗号中拆分字符串,并将每个结果字段分配给自己的字符串变量。在Perl中,我可以像这样优雅地做到这一点:

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

在C#中实现相同结果的最简单,最优雅的方法是什么?

我知道我可以分成一个阵列:

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

但是我必须通过索引访问这些字段,例如结果[2]。这很难阅读并且容易出错 - 考虑没有3个30个字段。出于这个原因,我更喜欢将每个字段值放在自己的命名变量中。

9 个答案:

答案 0 :(得分:8)

我同意。隐藏在Adapter类中的拆分似乎是一种很好的方法,并且很好地传达了您的意图:

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; }
}

答案 1 :(得分:7)

您可以使用元组(在.Net 4中添加)。 Tuples in 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>等创建元组。

另外......我真的不喜欢参数,所以你模拟使用返回多个值 元组(显然,也有不同类型)。 这样:

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(动态)(类似于ASP.NET MVC中的ViewBag)

答案 2 :(得分:3)

谁也无法抗拒Linq的一些精神错乱!

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"]);

答案 3 :(得分:2)

不是一线解决方案。但是,如果有一个额外的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,使用方式会有所不同。

答案 4 :(得分:1)

我推荐一本字典。

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]); 

答案 5 :(得分:1)

@pnvn对Unpack模式有一个好主意,但可以改进它在一次传递中迭代枚举,提供超过可枚举末尾的默认值,并以可预测的方式处理任何类型或大小的枚举

以下是使用C# 7 out variables feature的示例。

"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;
}

答案 6 :(得分:0)

在C#中没有内置的方法可以在Perl中进行多次赋值;但是,有多种解决方案可以通过正常路径将数据输入每个变量。

答案 7 :(得分:0)

我无法抗拒加入荒谬:)请不要使用这个“解决方案”,至少不是原样。

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"}) ;

答案 8 :(得分:0)

或者,出于可读性考虑,如果只想避免使用多余的变量名,则可以执行以下操作(C#7 +):

public static void Deconstruct<T>(this IList<T> self, out T v1, out T v2) {
    v1 = self.Count > 0 ? self[0] : default;
    v2 = self.Count > 1 ? self[1] : default;
}

在另一个静态类中,您在其中编写扩展方法。 然后像这样使用它:

var (a, b) = "1,2".Split(','); // a = "1"; b = "2";

很明显,可以将其扩展为两个以上的变量,但不幸的是,据我所知,您必须编写另一种方法。

例如:

public static class Ex {
    public static void Deconstruct<T>(this IList<T> self, out T v1, out T v2) {
        v1 = self.Count > 0 ? self[0] : default;
        v2 = self.Count > 1 ? self[1] : default;
    }

    public static void Deconstruct<T>(this IList<T> self, out T v1, out T v2, out T v3) {
        v1 = self.Count > 0 ? self[0] : default;
        v2 = self.Count > 1 ? self[1] : default;
        v3 = self.Count > 2 ? self[2] : default;
    }

    public static void Deconstruct<T>(this IList<T> self, out T v1, out T v2, out T v3, out T v4) {
        v1 = self.Count > 0 ? self[0] : default;
        v2 = self.Count > 1 ? self[1] : default;
        v3 = self.Count > 2 ? self[2] : default;
        v4 = self.Count > 3 ? self[3] : default;
    }
}

并像这样使用它:

var (a,_,_,d) = "1a,2b,3c,4d".Split(','); // a = "1a"; d = "4d";

作为副作用,现在您可以解构任何数组。

var (first,second) = new [] { 1,2 }; // first = 1; second = 2;