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#の方法は何ですか?
これは別の答えとして追加します。これは、すでに与えた答えとはかなり異なるためです。独自の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);
}
}
これはまったく同じ基本的な概念ではありませんが、探していることはこのラムダ式で実行できます。
_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[]
_に結果の値を入力します。
私の知る限り、これを行うためのフレームワークには組み込みのクラスはありません。自分でロールバックする必要があります。
それは難しいことではありません。素敵なC#バージョンはIEnumerableを実装しているので、
var scanner = new Scanner<int>(yourString);
foreach(int n in scanner)
; // your code
構文にできる限り近づけるために、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フレームワークが必要です。
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)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の組み合わせ)の一種です。