我有一个字符串,其中有几个字段由特定字符分隔,如下所示:
A,B,C
我想在逗号中拆分字符串,并将每个结果字段分配给自己的字符串变量。在Perl中,我可以像这样优雅地做到这一点:
my ($varA, $varB, $varC) = split (/,/, $string);
在C#中实现相同结果的最简单,最优雅的方法是什么?
我知道我可以分成一个阵列:
string[] results = string.Split(',');
但是我必须通过索引访问这些字段,例如结果[2]。这很难阅读并且容易出错 - 考虑没有3个30个字段。出于这个原因,我更喜欢将每个字段值放在自己的命名变量中。
答案 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;