C#中的Scanner类是否等同于字符串?

时间:2009-04-06 16:47:16

标签: c# java string java.util.scanner

在Java中,我可以向扫描器传递一个字符串,然后我可以做一些方便的事情,例如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#'这样做的方法?

7 个答案:

答案 0 :(得分:23)

我将把它作为一个单独的答案添加,因为它与我已经给出的答案截然不同。以下是您可以开始创建自己的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;
  }
}

答案 1 :(得分:4)

使用已经给出的部分答案,我创建了一个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);
    }

}

答案 2 :(得分:3)

虽然这不是完全相同的基本概念,但您正在寻找的是这个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()调用将这个抽象的可枚举类转换为具体的数组。

因此,最后,这会拆分string,然后将每个元素转换为int,并使用结果值填充int[]

答案 3 :(得分:3)

据我所知,框架中没有用于执行此操作的内置类。你必须自己动手。

这不会太难。一个不错的C#版本可能会实现IEnumerable,所以你可以说:

var scanner = new Scanner<int>(yourString);
foreach(int n in scanner)
    ; // your code

答案 4 :(得分:2)

为了尽可能接近您的语法,如果您只对一种类型感兴趣(示例中为“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框架。

答案 5 :(得分:1)

您可以使用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...

答案 6 :(得分:0)

我会以两种方式中的一种方式执行此操作,具体取决于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的组合)的组合。