2011-12-10 61 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