是否有与 C# 中的 Scanner 类等效的字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/722270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 22:32:07  来源:igfitidea点击:

Is there an equivalent to the Scanner class in C# for strings?

c#javastringjava.util.scanner

提问by mmcdole

In Java I can pass a Scanner a string and then I can do handy things like, scanner.hasNext()or scanner.nextInt(), scanner.nextDouble()etc.

在Java中,我可以通过一个扫描一个字符串,然后我可以做的得心应手之类的东西,scanner.hasNext()或者scanner.nextInt()scanner.nextDouble()等。

This allows some pretty clean code for parsing a string that contains rows of numbers.

这允许一些非常干净的代码来解析包含数字行的字符串。

How is this done in C# land?

这是如何在 C# 领域完成的?

If you had a string that say had:

如果你有一个字符串,上面写着:

"0 0 1 22 39 0 0 1 2 33 33"

In Java I would pass that to a scanner and do a

在 Java 中,我会将其传递给扫描仪并执行

while(scanner.hasNext()) 
    myArray[i++] = scanner.nextInt();

Or something very similar. What is the C#' ish way to do this?

或者非常相似的东西。什么是 C#' ish 的方式来做到这一点?

回答by Adam Robinson

While this isn't the exact same fundamental concept, what you're looking for can be done with this lambda expression:

虽然这不是完全相同的基本概念,但您可以使用此 lambda 表达式完成您要查找的内容:

string foo = "0 0 1 22 39 0 0 1 2 33 33";

int[] data = foo.Split(' ').Select(p => int.Parse(p)).ToArray();

What this does is first Splitthe string, using a space as a delimiter. The Selectfunction then allows you to specify an alias for a given member in the array (which I referred to as 'p' in this example), then perform an operation on that member to give a final result. The ToArray()call then turns this abstract enumerable class into a concrete array.

这样做是首先Splitstring,使用空格作为分隔符。Select然后,该函数允许您为数组中的给定成员指定别名(p在本例中我将其称为“ ”),然后对该成员执行操作以给出最终结果。然后ToArray()调用将这个抽象的可枚举类转换为一个具体的数组。

So in this end, this splits the string, then converts each element into an intand populates an int[]with the resulting values.

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

回答by driis

To my knowledge, there are no built in classes in the framework for doing this. You would have to roll your own.

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

That would not be too hard. A nice C# version might implement IEnumerable so you could say:

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

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

回答by BlueMonkMN

I would do this in one of a couple ways depending on whether 1) you are using the latest .NET framework with LINQ support and 2) you know the values are valid integers. Here's a function to demonstrate both:

我会根据以下几种方式之一执行此操作,具体取决于 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();
  }

Based on comments in other answer(s), I assume you need the validation. After reading those comments, I think the closest thing you'll get is int.TryParse and double.TryParse, which is kind of a combination of hasNextInt and nextInt (or a combination of hasNextDouble and nextDouble).

根据其他答案中的评论,我假设您需要验证。阅读完这些评论后,我认为最接近的是 int.TryParse 和 double.TryParse,它是 hasNextInt 和 nextInt 的组合(或 hasNextDouble 和 nextDouble 的组合)。

回答by Fraser

You could use linq to accomplish this like so:

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

回答by David Gladfelter

To get as close as possible to your syntax, this'll work if you're only interested in one type ("int" in the example):

为了尽可能接近您的语法,如果您只对一种类型(示例中的“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);
   }            
}

Here's an even more whiz-bang version that allows you to access any type that is supported by string's IConvertible implementation:

这是一个更神奇的版本,它允许您访问字符串的 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)));
    }            
}

Just pass a different type to the "typeof" operator in the while loop to choose the type.

只需将不同的类型传递给 while 循环中的“typeof”运算符即可选择类型。

These both require the latest versions of C# and the .NET framework.

这些都需要最新版本的 C# 和 .NET 框架。

回答by BlueMonkMN

I'm going to add this as a separate answer because it's quite distinct from the answer I already gave. Here's how you could start creating your own Scanner class:

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

回答by Dennis

Using part of the answers already given, I've created a StringReaderthat can extract Enumand any data type that implements IConvertible.

使用已经给出的部分答案,我创建了一个StringReader可以提取Enum和实现IConvertible.

Usage

用法

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

Implementation

执行

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

}