web-dev-qa-db-ja.com

文字列用のC#の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#の方法は何ですか?

32
mmcdole

これは別の答えとして追加します。これは、すでに与えた答えとはかなり異なるためです。独自の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;
  }
}
24
BlueMonkMN

すでに与えられた回答の一部を使用して、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);
    }

}
4
Dennis

これはまったく同じ基本的な概念ではありませんが、探していることはこのラムダ式で実行できます。

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

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

これが最初に行うことは、スペースを区切り文字として使用するSplitstringです。次に、Select関数を使用して、配列内の特定のメンバーのエイリアス(この例では「p」と呼びます)を指定し、そのメンバーに対して操作を実行して、最終結果。 ToArray()呼び出しは、この抽象列挙可能クラスを具象配列に変換します。

したがって、この目的で、これはstringを分割し、各要素をintに変換して、_int[]_に結果の値を入力します。

3
Adam Robinson

私の知る限り、これを行うためのフレームワークには組み込みのクラスはありません。自分でロールバックする必要があります。

それは難しいことではありません。素敵なC#バージョンはIEnumerableを実装しているので、

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

構文にできる限り近づけるために、1つのタイプ(例では「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フレームワークが必要です。

2

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...
1
Fraser

これは、1)LINQをサポートする最新の.NETフレームワークを使用しているかどうか、および2)値が有効な整数であるかどうかに応じて、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の組み合わせ)の一種です。

0
BlueMonkMN