2011-12-10 5 views
2

나는 D를 배우려고 노력하고 있지만, 문서가 부족하거나 (그것을 이해하고있다) 어려움을 겪고 있으므로 여기에 왔습니다. 나는 이미 오늘과는 다른, 그러나 무관계 한 질문을했다.D 문자열을 파싱하기 D

어쨌든, 여기 간다 :

내가 다른 것들에 대한 문자열을 구문 분석하고 싶습니다. 더 라벨이없는 경우 필수 공백이,

[<label>] <mnemonic> [parameters] 

:

문자열 형식은 같은 것입니다. 매개 변수는 쉼표로 분리 할 수 ​​있습니다. 매개 변수 유형은 연상 기호에 따라 다릅니다.

나를 돕기 위해 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

문자열이 앞으로 이동합니까? 또한, 개행을 치면 어떻게 될까? 또한, 문자열을 두 번 통과하지 않습니까? 아, 그리고 .idup없이 작동하는 것 같습니다. 이유를 설명해 주시겠습니까? – Matej

+0

이 작은 함수는 첫 번째 공백의 위치를 ​​저장하고 ";"에 대해 동일한 작업을 수행합니다. 작은 위치는 슬라이스에 필요한 끝을 보여줍니다. – bioinfornatics

+0

흥미 롭습니다, 감사합니다. 하지만 countWill과 함께 "isWhite"함수를 어떻게 사용합니까? 나는 그것을 작동시키는 것처럼 보일 수 없다. 나는 "isWhite"의 부정을 원한다. – Matej

2

첫째, std.conv.parse는 의미로 해석되지 문자열로 물건을 변환하는 것입니다 문자열을 분리하고 이해하는 것. 필요한 솔루션의 복잡성은 형식 문자열의 문법의 복잡성에 따라 달라집니다. std.string.split을 보면 기본적으로 공백에 입력을 분할하고 단어 배열을 반환합니다. 형식이 너무 복잡하면 , 당신은 할 수 있습니다 캡처와

  1. 사용 정규식 : http://d-programming-language.org/phobos/std_regex.html#RegexMatch

  2. 은 문자로 문자를 전진하고 필요한 정보를 추출하여 자신의 파서를 작성.

+0

나는 그것들을 보았지만 정규 표현식은 조금 과장된 것처럼 보였다. 분할은 내가 원하는 것을하는 것처럼 보이지만 효율적입니까? 내가 데이터를 두 번 읽는 것 같아. 또한 D의 문자열에서 16 진수를 얻는 방법을 알려주시겠습니까? Tango 라이브러리에서 이와 비슷한 것을 발견했지만 Phobos와 D2를 사용하고 있습니다. – Matej

+1

split이 작업을 수행하지만 데이터를 두 번 다루는 것에 대해 우려하는 경우 (매우 큰 실시간 작업을 수행하지 않는 한 내가하지 않을 것입니다) std.string.munch를 고려하십시오. –

+0

글쎄, 나는이 옵션 중 하나에 시간이있을 때 물건을 다시 작성합니다. countUntil 하나는 꽤 추악하지만 융통성이 있습니다. 감사. – Matej