2011-12-10 19 views
2

私はDを学ぼうとしていますが、ドキュメントの不足(または私の理解)に苦しんでいるので、ここに来ました。私はすでに、以前は今までとは異なるが無関係な質問をしました。Dの文字列の解析D

とにかく、ここに行く:

私は別のもののために文字列を解析したいと思います。ラベルが存在しない場合、必須の空白がある

[<label>] <mnemonic> [parameters] 

文字列の形式は次のようなものです。パラメータはコンマで区切ることができます。パラメータタイプはニーモニックに依存します。

PhobosライブラリのPhobosライブラリのstd.conv: parseを使用して私の手助けをしたいと思いますが、どちらかの端にある空白で区切られた文字のように、「単語」を解析する方法に関するドキュメントは理解できません。整数などの場合はint i = parse!int(line)として正常に動作します。しかし、もし私がstring s = parse!string(line)をしなければならないと、それは行全体をつかむでしょう。

私はCでこれを書いたときと同じように、char**(またはref string)をデータ型としてコールドパースします。しかし、私はDを学習しています。

私は手動でそれを行うには、このような何かを試してみました:

string get_word(ref string s) 
{ 
     int i = 0; 
     while (i < s.length && isAlphaNum(s[i])) 
       i++; 

     string word = s[0 .. i]; 
     s = s[i+1 .. $]; 
     return word; 
} 

が、これはそれを行うには良い方法ですか?よりクリーンな方法がありますか?より速い方法?おそらくもっと安全な方法でしょうか? i+1のインデックスが必ず存在するかどうかはわかりません。

ありがとうございました!

Dの私の信念は、私があらゆる種類の問題に遭遇したので、すでにわずかに減少しています。しかし、その道は確かに価値があるだろう。

答えて

1

コードはその場で書いている

import std.string; 
import std.stdio; 
import std.algorithm; 
import std.math; 

enum string[] separators = [ " ", "\t", ",", ";", "\n", "\r\n" ]; 

string get_word(ref string s){ 
    string token; 
    sizediff_t storePositions[separators.length + 1]; // set size array to the number of separator in array "separators" and latest field for current string lenght 
    foreach(i, separator; separators){    // compute position for each separator 
     sizediff_t position = countUntil(s, separator); 
     if(position == -1) position = sizediff_t.max; 
     storePositions[i] = position; 
    } 
    storePositions[ $ -1 ] = s.length; 
    sizediff_t end = reduce!min(storePositions); 
    token    = s[0 .. end].idup; 
    writefln("%s | %d", s, end); 
    return token; 
} 

void main(string[] args){ 
    string s  = "a long;string\tyeah\n strange; ok"; 
    bool isRunning= true; 
    size_t start = 0; 
    writefln("parse: %s", s); 
    while(isRunning){ 
     string result = get_word(s[ start .. $]); 
     if(result == "") 
      isRunning = false; 
     else{ 
      start += result.length + 1; 
      result = get_word(s[ start .. $]); 
     } 
     writefln("token: %s, position: %d", result, start); 
     writeln("----"); 
    } 
} 

出力:すべての

parse: a long;string yeah 
strange; ok 
a long;string yeah 
strange; ok | 1 
long;string yeah 
strange; ok | 4 
token: long, position: 2 
---- 
long;string yeah 
strange; ok | 4 
string yeah 
strange; ok | 6 
token: string, position: 7 
---- 
string yeah 
strange; ok | 6 
yeah 
strange; ok | 4 
token: yeah, position: 14 
---- 
yeah 
strange; ok | 4 
strange; ok | 0 
token: , position: 19 
---- 
strange; ok | 0 
token: , position: 19 

+0

これは文字列を進めますか?また、改行に当たったらどうなりますか?また、それは文字列を2回通過しませんか? ああ、 '.idup 'の有無にかかわらずうまくいくように思えますが、その理由を説明できますか? – Matej

+0

この小さな関数は、最初の空白の位置を保存し、 ";"と同じことをします。小さな位置は、スライスに使用する必要がある最後を示します。 – bioinfornatics

+0

面白い、ありがとう。しかし、私はcountUntilで "isWhite"関数をどのように使用しますか?私はそれを動作させるように見えることはできません。私は "isWhite"の否定をしたい。 – Matej

2

まず、std.conv.parseは、ある意味で解析していない、文字列に物事を変換するものです文字列を分離して理解すること。必要なソリューションの複雑さは、フォーマット文字列の文法の複雑さに依存します。 std.string.splitを見てください。デフォルトでは、あなたの入力を空白に分割し、単語の配列を返します。フォーマットが複雑すぎる場合 は、次のことができます。キャプチャと

  1. 使用正規表現:http://d-programming-language.org/phobos/std_regex.html#RegexMatch

  2. は文字ずつ前進し、必要な情報を抽出し、独自のパーサを書きます。

+0

私もそれらを見てきましたが、正規表現は少し過酷なようでした。スプリットは私の望むことをするようですが、効率的ですか?私はデータを2回見ているようです。 また、Dの文字列から16進数を取得する方法を教えてください。私はタンゴの図書館でこれを見つけましたが、私はPhobosとD2を使用しています。 – Matej

+1

splitがジョブを実行しても、データを2回カバリングすることに懸念がある場合(非常に大規模なリアルタイムジョブを実行しない限り)、std.string.munchを検討してください。 –

+0

さて、これらのオプションのうちの1つに時間があるとき、私はものを書き換えます。 countUntil 1はかなり醜いですが、柔軟性はあります。ありがとう。 – Matej