2012-01-15 34 views
7

Tôi nhận được phản hồi từ một dịch vụ như sau. Cách phân tích cú pháp này thành một số Map? Lần đầu tiên tôi nghĩ về việc chia tách ở khoảng trắng nhưng nó không hoạt động vì giá trị có thể chứa khoảng trắng, ví dụ: xem xét giá trị của SA chính trong phản hồi dưới đây.Có cách nào đơn giản để phân tích cú pháp văn bản này thành Bản đồ

Một tùy chọn tôi nghĩ là chia nhỏ khoảng trắng được cung cấp ký tự trước là dấu ngoặc kép. Không chắc chắn làm thế nào để viết regex cho điều này mặc dù.

TX = "0000000000108000001830001" FI = "" hệ điều hành = "8" CI = "QU01SF1S2032" AW = "SSS" SA = "1525 Windward Concourse"

Trả lời

4

Parse tại dấu ngoặc kép. Thậm chí bạn có thể sử dụng cụm từ thông dụng để tìm mỗi cặp khóa/giá trị, giả sử mỗi giá trị nằm trong dấu ngoặc kép. Câu hỏi duy nhất của tôi là, các quy tắc cho một giá trị có chứa các trích dẫn nhúng là gì? (Họ đã trốn thoát bằng '\' hay như vậy Cho dù, đây không phải hiện hạch toán vào bên dưới ...?)

Ví dụ:

(\w+)="([^"]*)" 

này thậm chí sẽ cung cấp cho bạn các nhóm # 1 và # 2 có thể được sử dụng để cung cấp khóa và giá trị tương ứng.

Chạy vòng lặp này, sử dụng phương thức Matcher.find() của Java, cho đến khi bạn tìm thấy tất cả các cặp.

Mẫu mã:

String input = "TX=\"0000000000108000001830001\" FI=\"\" OS=\"8\" CI=\"QU01SF1S2032\" AW=\"SSS\" SA=\"1525 Windward Concourse\""; 

Pattern p = Pattern.compile("\\s*(\\w+)=\"([^\"]*)\"\\s*"); 

Matcher m = p.matcher(input); 
while(m.find()){ 
    System.out.println(m.group(1)); 
    System.out.println(m.group(2)); 
} 

Output:

TX 
0000000000108000001830001 
FI 

OS 
8 
CI 
QU01SF1S2032 
AW 
SSS 
SA 
1525 Windward Concourse 
+2

Geez, chỉ cần sử dụng dấu nháy đơn; nó được gắn thẻ Groovy :) –

+0

@DaveNewton - Chúng tôi sẽ để nó như là một bài tập cho OP. :-) – ziesemer

+0

@ziesemer - +1. Nhưng tôi nhận được valaue sau khi '=' in với quoes đôi là "0000000000108000001830001" –

2

StreamTokenizer là nhanh chóng, mặc dù tôi đã không sử dụng tính năng quoteChar(). Ví dụ có thể được tìm thấy here, herehere.

Console:

 
TX=0000000000108000001830001 
FI= 
OS=8 
CI=QU01SF1S2032 
AW=SSS 
SA=1525 Windward Concourse 
Count: 6 
0.623 ms 

Code:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.StreamTokenizer; 
import java.io.StringReader; 

/** @see https://stackoverflow.com/questions/8867325 */ 
public class TokenizerTest { 

    private static final String s = "" 
     + "TX=\"0000000000108000001830001\" FI=\"\" OS=\"8\" " 
     + "CI=\"QU01SF1S2032\" AW=\"SSS\" SA=\"1525 Windward Concourse\""; 
    private static final char equal = '='; 
    private static final char quote = '"'; 
    private static StreamTokenizer tokens = new StreamTokenizer(
     new BufferedReader(new StringReader(s))); 

    public static void main(String[] args) { 
     long start = System.nanoTime(); 
     tokenize(); 
     long stop = System.nanoTime(); 
     System.out.println((stop - start)/1000000d + " ms"); 
    } 

    private static void tokenize() { 
     tokens.ordinaryChar(equal); 
     tokens.quoteChar(quote); 
     try { 
      int count = 0; 
      int token = tokens.nextToken(); 
      while (token != StreamTokenizer.TT_EOF) { 
       if (token == StreamTokenizer.TT_WORD) { 
        System.out.print(tokens.sval); 
        count++; 
       } 
       if (token == equal) { 
        System.out.print(equal); 
       } 
       if (token == quote) { 
        System.out.println(tokens.sval); 
       } 
       token = tokens.nextToken(); 
      } 
      System.out.println("Count: " + count); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

Điều cần biết về StreamTokenizer –

+0

Tôi chỉ cần _had_ để thử 'quoteChar()' ; ở trên. – trashgod

+0

Tôi nghĩ giải pháp này quá phức tạp. Trừ khi có một hạn chế hiệu suất lớn, tôi khuyên bạn nên sử dụng một giải pháp đơn giản hơn, như sử dụng regex (và nếu hiệu suất _is_ là một ràng buộc, nó sẽ được lược tả để xem điều này có thực sự nhanh hơn regex hay không). – epidemian

3

Bởi vẻ của văn bản có vẻ như nó có thể là một XML. Đó có phải là, hoặc là văn bản phản ứng thô của dịch vụ? Nếu đó là một XML, bạn có thể phân tích nó một cách dễ dàng với XmlSlurper Groovy của:

def input = '<root TX="0000000000108000001830001" FI="" OS="8" CI="QU01SF1S2032" AW="SSS" SA="1525 Windward Concourse"></root>' 
def xml = new XmlSlurper().parseText(input) 

def map = xml.attributes() 

Biến map sẽ [CI:QU01SF1S2032, AW:SSS, TX:0000000000108000001830001, OS:8, FI:, SA:1525 Windward Concourse]

Nếu nó không phải là một XML, bạn có thể làm theo ziesemer's answer và sử dụng một regex. Một phiên bản groovier của câu trả lời của mình mà tạo ra một Map sẽ là:

def input = 'TX="0000000000108000001830001" FI="" OS="8" CI="QU01SF1S2032" AW="SSS" SA="1525 Windward Concourse"' 
def match = input =~ /(\w+)="([^"]*)"/ 

def map = [:] 
match.each { 
    map[it[1]] = it[2] 
} 

Kết quả của map sẽ giống như trước.

+0

Bạn cũng có thể làm: 'def map = (match as List) .collectEntries {[(nó [1]): nó [2]]}' –

+0

@tim_yates Nice! Tôi đã thử gọi 'collectEntries' trên đối tượng' match', nhưng nó không có phương thức đó, chỉ có các phương thức lặp tiêu chuẩn. Tôi không nghĩ đến việc chuyển nó thành một 'Danh sách' trước. BTW, một 'inject' cũng có thể thực hiện thủ thuật = D – epidemian

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