提问人:mmcdole 提问时间:4/7/2009 最后编辑:Dhanukammcdole 更新时间:6/15/2015 访问量:64089
是否有与 C# 中字符串的 Scanner 类等效的类?
Is there an equivalent to the Scanner class in C# for strings?
问:
在 Java 中,我可以向 Scanner 传递一个字符串,然后我可以做一些方便的事情,比如 or 等。scanner.hasNext()
scanner.nextInt()
scanner.nextDouble()
这允许一些非常干净的代码来解析包含数字行的字符串。
这是如何在 C# 领域完成的?
如果你有一个字符串,上面写着:
"0 0 1 22 39 0 0 1 2 33 33"
在 Java 中,我会将其传递给扫描仪并执行
while(scanner.hasNext())
myArray[i++] = scanner.nextInt();
或者非常相似的东西。C# 的方法来做到这一点?
答:
虽然这不是完全相同的基本概念,但您可以使用以下 lambda 表达式来完成您要查找的内容:
string foo = "0 0 1 22 39 0 0 1 2 33 33";
int[] data = foo.Split(' ').Select(p => int.Parse(p)).ToArray();
这首先要做的是 ,使用空格作为分隔符。然后,该函数允许您为数组中的给定成员指定别名(在此示例中我将其称为“”),然后对该成员执行操作以给出最终结果。然后,该调用将这个抽象的可枚举类转换为具体数组。Split
string
Select
p
ToArray()
因此,最后,这会拆分 ,然后将每个元素转换为 ,并用结果值填充 an。string
int
int[]
评论
据我所知,框架中没有用于执行此操作的内置类。你必须自己滚动。
这不会太难。一个好的 C# 版本可能会实现 IEnumerable,因此你可以说:
var scanner = new Scanner<int>(yourString);
foreach(int n in scanner)
; // your code
评论
我会通过以下几种方式之一来执行此操作,具体取决于 1) 您是否使用的是支持 LINQ 的最新 .NET 框架,以及 2) 您是否知道这些值是有效的整数。下面是一个演示两者的函数:
int[] ParseIntArray(string input, bool validateRequired)
{
if (validateRequired)
{
string[] split = input.Split();
List<int> result = new List<int>(split.Length);
int parsed;
for (int inputIdx = 0; inputIdx < split.Length; inputIdx++)
{
if (int.TryParse(split[inputIdx], out parsed))
result.Add(parsed);
}
return result.ToArray();
}
else
return (from i in input.Split()
select int.Parse(i)).ToArray();
}
根据其他答案中的评论,我认为您需要验证。看完这些评论后,我认为你会得到的最接近的东西是 int。TryParse 和 double。TryParse,它是 hasNextInt 和 nextInt 的组合(或 hasNextDouble 和 nextDouble 的组合)。
您可以使用 linq 来实现此目的,如下所示:
string text = "0 0 1 22 39 0 0 1 2 33 33";
text.Where(i => char.IsNumber(i)).Write(); // do somthing usefull here...
为了尽可能接近您的语法,如果您只对一种类型感兴趣(示例中的“int”),这将起作用:
static void Main(string[] args)
{
if (args.Length == 0) { args = new string[] { "3", "43", "6" }; }
IEnumerator<int> scanner = (from arg in args select int.Parse(arg)).GetEnumerator();
while (scanner.MoveNext())
{
Console.Write("{0} ", scanner.Current);
}
}
下面是一个更奇特的版本,它允许你访问字符串的 IConvertible 实现支持的任何类型:
static void Main(string[] args)
{
if (args.Length == 0) { args = new string[] { "3", "43", "6" }; }
var scanner = args.Select<string, Func<Type, Object>>((string s) => {
return (Type t) =>
((IConvertible)s).ToType(t, System.Globalization.CultureInfo.InvariantCulture);
}).GetEnumerator();
while (scanner.MoveNext())
{
Console.Write("{0} ", scanner.Current(typeof(int)));
}
}
只需将不同的类型传递给 while 循环中的“typeof”运算符即可选择类型。
这两者都需要最新版本的 C# 和 .NET Framework。
我将把它作为一个单独的答案添加,因为它与我已经给出的答案完全不同。以下是如何开始创建自己的 Scanner 类:
class Scanner : System.IO.StringReader
{
string currentWord;
public Scanner(string source) : base(source)
{
readNextWord();
}
private void readNextWord()
{
System.Text.StringBuilder sb = new StringBuilder();
char nextChar;
int next;
do
{
next = this.Read();
if (next < 0)
break;
nextChar = (char)next;
if (char.IsWhiteSpace(nextChar))
break;
sb.Append(nextChar);
} while (true);
while((this.Peek() >= 0) && (char.IsWhiteSpace((char)this.Peek())))
this.Read();
if (sb.Length > 0)
currentWord = sb.ToString();
else
currentWord = null;
}
public bool hasNextInt()
{
if (currentWord == null)
return false;
int dummy;
return int.TryParse(currentWord, out dummy);
}
public int nextInt()
{
try
{
return int.Parse(currentWord);
}
finally
{
readNextWord();
}
}
public bool hasNextDouble()
{
if (currentWord == null)
return false;
double dummy;
return double.TryParse(currentWord, out dummy);
}
public double nextDouble()
{
try
{
return double.Parse(currentWord);
}
finally
{
readNextWord();
}
}
public bool hasNext()
{
return currentWord != null;
}
}
评论
使用已经给出的部分答案,我创建了一个可以提取和实现 .StringReader
Enum
IConvertible
用法
using(var reader = new PacketReader("1 23 ErrorOk StringValue 15.22")
{
var index = reader.ReadNext<int>();
var count = reader.ReadNext<int>();
var result = reader.ReadNext<ErrorEnum>();
var data = reader.ReadNext<string>();
var responseTime = reader.ReadNext<double>();
}
实现
public class PacketReader : StringReader
{
public PacketReader(string s)
: base(s)
{
}
public T ReadNext<T>() where T : IConvertible
{
var sb = new StringBuilder();
do
{
var current = Read();
if (current < 0)
break;
sb.Append((char)current);
var next = (char)Peek();
if (char.IsWhiteSpace(next))
break;
} while (true);
var value = sb.ToString();
var type = typeof(T);
if (type.IsEnum)
return (T)Enum.Parse(type, value);
return (T)((IConvertible)value).ToType(typeof(T), System.Globalization.CultureInfo.CurrentCulture);
}
}
评论