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

发布于 2024-07-16 09:06:37 字数 443 浏览 3 评论 0原文

在Java中,我可以向扫描仪传递一个字符串,然后我可以做一些方便的事情,例如,scanner.hasNext()scanner.nextInt()scanner.nextDouble () 等。

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

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

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

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

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

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

或非常类似的操作。 C# 风格的方法是什么?

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.

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

How is this done in C# land?

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

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

嘿哥们儿 2024-07-23 09:06:37

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

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:

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;
  }
}
荆棘i 2024-07-23 09:06:37

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

}

Using part of the answers already given, I've created a StringReader that can extract Enum and any data type that implements 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);
    }

}
伴随着你 2024-07-23 09:06:37

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

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

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

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

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

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

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 Split the string, using a space as a delimiter. The Select function 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.

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

比忠 2024-07-23 09:06:37

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

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

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

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:

var scanner = new Scanner<int>(yourString);
foreach(int n in scanner)
    ; // your code
眼中杀气 2024-07-23 09:06:37

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

这是一个更加出色的版本,允许您访问支持的任何类型通过 string 的 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 框架。

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

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:

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.

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

野侃 2024-07-23 09:06:37

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

You could use linq to accomplish this like so:

string text = "0 0 1 22 39 0 0 1 2 33 33";
text.Where(i => char.IsNumber(i)).Write(); // do somthing usefull here...
鸠书 2024-07-23 09:06:37

我会通过以下几种方式之一来执行此操作,具体取决于 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 的组合)。

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:

  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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文