2012-04-15 39 views
6

Đây là một đoạn trích từ cuộc thảo luận trong some other question.Phân tích cú pháp mà không cần tách chuỗi

Giả sử tôi phải phân tích cú pháp một số lượng lớn các chuỗi rất dài. Mỗi chuỗi chứa một chuỗi gồm double s (trong phần trình bày văn bản, tất nhiên) được phân tách bằng khoảng trắng. Tôi cần phải phân tích cú pháp double s thành một số List<double>.

Kỹ thuật phân tích cú pháp chuẩn (sử dụng string.Split + double.TryParse) có vẻ khá chậm: đối với mỗi số chúng ta cần phân bổ chuỗi.

Tôi đã cố gắng làm cho nó giống như C-cách: tính toán các chỉ số bắt đầu và kết thúc của các chất nền có chứa các con số, và phân tích nó "tại chỗ", mà không tạo chuỗi bổ sung. (Xem http://ideone.com/Op6h0, dưới đây cho thấy một phần có liên quan.)

int startIdx, endIdx = 0; 
while(true) 
{ 
    startIdx = endIdx; 
    // no find_first_not_of in C# 
    while (startIdx < s.Length && s[startIdx] == ' ') startIdx++; 
    if (startIdx == s.Length) break; 
    endIdx = s.IndexOf(' ', startIdx); 
    if (endIdx == -1) endIdx = s.Length; 
    // how to extract a double here? 
} 

Có một tình trạng quá tải của string.IndexOf, chỉ tìm kiếm trong một chuỗi nào đó, nhưng tôi không thể tìm thấy một phương pháp để phân tích cú đúp của chuỗi con, mà không thực sự giải nén mà chuỗi con đầu tiên.

Có ai có ý tưởng không?

+5

Các bạn đã chứng minh điều này thực sự là một nút cổ chai? Tôi không * biết * của bất kỳ cách nào để làm nó off-hand, nhưng tôi chắc chắn muốn có một số bằng chứng của nó là một vấn đề trước khi vi tối ưu hóa. –

+0

@Jon: không thực sự. Câu hỏi được dựa trên thảo luận tại câu hỏi được liên kết (http://stackoverflow.com/questions/10053449/extract-numbers-from-string). Xin lỗi vì chuyện đó. – Vlad

+0

Đủ công bằng. Tôi nghi ngờ rằng một thói quen phân tích cú pháp viết tay sẽ chậm hơn so với phương pháp có thể được tối ưu hóa với rất nhiều kinh nghiệm mà nhóm BCL đã đưa ra :) –

Trả lời

7

không có API được quản lý để phân tích cú pháp đôi từ chuỗi con. Tôi đoán là phân bổ chuỗi sẽ không đáng kể so với tất cả các hoạt động điểm nổi trong double.Parse.

Dù sao, bạn có thể lưu phân bổ bằng cách tạo chuỗi "bộ đệm" sau khi chiều dài 100 chỉ bao gồm khoảng trắng. Sau đó, đối với mọi chuỗi bạn muốn phân tích cú pháp, bạn sao chép các ký tự vào chuỗi bộ đệm này bằng cách sử dụng mã không an toàn. Bạn điền vào chuỗi bộ đệm với khoảng trắng. Và để phân tích cú pháp, bạn có thể sử dụng NumberStyles.AllowTrailingWhite, điều này sẽ khiến cho khoảng trắng cuối bị bỏ qua.

Bắt một con trỏ đến chuỗi thực sự là một hoạt động hỗ trợ đầy đủ:

string l_pos = new string(' ', 100); //don't write to a shared string! 
    unsafe 
    { 
     fixed (char* l_pSrc = l_pos) 
     {    
       // do some work 
     } 
    } 

C# có cú pháp đặc biệt để ràng buộc một chuỗi đến một char *.

+0

Tôi có hiểu chính xác không: bạn có nghĩa là sửa đổi 'System.String' được cho là không thay đổi được với mã không an toàn? – Vlad

+0

Sẽ không phân tích cú pháp tất cả khoảng trắng đó làm cho điều này thực sự chậm hơn so với phân bổ chuỗi mới mỗi lần? – svick

+0

@Vlad, vâng, bạn có thể làm điều đó. Chỉ cần không vượt qua chuỗi đó và giữ riêng tư. Bằng cách đó bạn không vi phạm các giả định mã khác tạo ra. StringBuilder sử dụng kỹ thuật này trong nội bộ. Khi bạn ToString một StringBuilder nó chỉ đưa cho bạn bộ đệm bên trong của nó. StringBuilder.ToString thường là O (1). – usr

2

nếu bạn muốn làm điều đó thật nhanh, tôi sẽ sử dụng một máy nhà nước

này có thể trông giống như:

enum State 
{ 
    Separator, Sign, Mantisse etc. 
} 
State CurrentState = State.Separator; 
int Prefix, Exponent, Mantisse; 
foreach(var ch in InputString) 
{ 
    switch(CurrentState) 
    { // set new currentstate in dependence of ch and CurrentState 
     case Separator: 
      GotNewDouble(Prefix, Exponent, Mantisse); 


    } 

} 
+0

Bạn có nghĩa là phân tích cú pháp thủ công, mà không cần sử dụng TryParse không? – Vlad

+0

vâng, nếu bạn đang sử dụng TryParse, bạn cần mỗi lần một thể hiện chuỗi mới. sau đó bạn có hành vi tương tự như var values ​​= string.Split ('') .Select (s => double.Parse (s)). ToArray(); – user287107

+0

tốt, phân tích cú pháp thủ công có xu hướng chậm và lỗi, tôi muốn tránh tái phát minh bánh xe nếu có thể. – Vlad

Các vấn đề liên quan