2011-12-10 101 views
2

我在努力學習D,但由於缺乏文檔(或者我對它的理解)而掙扎,所以我來到了這裏。我今天早些時候已經問過一個不同但不相關的問題。解析D中的一個字符串

無論如何,這裏有雲:

我想解析爲不同的東西的字符串。

字符串格式是一樣的東西:

[<label>] <mnemonic> [parameters] 

如果沒有標籤,沒有強制性的空白。參數可以用逗號分隔。參數類型取決於助記符。

我想使用Phobos庫中的std.conv: parse來幫助我,但我無法理解關於如何解析「單詞」的文檔,例如,在任何一端由空白分隔的某些字符。它適用於整數和int i = parse!int(line)。但是,如果我要做string s = parse!string(line)它會抓住整條線。

我用手解析這個,使用char**(或者ref string)作爲數據類型,就像我在C中寫這個時一樣。但是我正在學習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

這是否推進字符串?另外,如果它碰到換行符,會發生什麼?另外,它不是通過兩次字符串? 哦,並且它似乎與'.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

我也見過這些,但正則表達式似乎有點矯枉過正。斯普利特似乎做了我想要的,但效率如何?好像我會兩次瀏覽數據。 另外,你能告訴我如何從D中的字符串獲得一個十六進制數字嗎?我在Tango圖書館發現了類似的東西,但我使用了Phobos和D2。 – Matej

+1

如果拆分完成這項工作,但您擔心兩次覆蓋數據(我不會這麼做,除非您正在執行非常大的實時作業),請考慮std.string.munch。 –

+0

好吧,當我有時間進入其中一個選項時,我會重寫這些東西。這個數字雖然很靈活,但相當醜陋。謝謝。 – Matej