2012-02-11 48 views
9

Tôi đang viết một trình phân tích cú pháp cho một ngôn ngữ truy vấn bằng cách sử dụng PyParsing, và tôi đã bị mắc kẹt trên (những gì tôi tin là) một vấn đề với lookaheads. Một loại mệnh đề trong truy vấn được dùng để chia chuỗi thành 3 phần (tên trường, toán tử, giá trị) sao cho trường đó là một từ, toán tử là một hoặc nhiều từ và giá trị là một từ, chuỗi trích dẫn hoặc danh sách được ngoặc đơn những cái nàyPyParsing lookaheads và biểu thức tham lam

Dữ liệu của tôi trông giống như

author is william 
author is 'william shakespeare' 
author is not shakespeare 
author is in (william,'the bard',shakespeare) 

Và phân tích cú pháp hiện tại của tôi cho điều khoản này được viết như sau:

fieldname = Word(alphas) 

operator = OneOrMore(Word(alphas)) 

single_value = Word(alphas)^QuotedString(quoteChar="'") 
list_value = Literal("(") + Group(delimitedList(single_value)) + Literal(")") 
value = single_value^list_value 

clause = fieldname + originalTextFor(operator) + value 

Rõ ràng điều này không thành do thực tế là các yếu tố operator là tham lam và sẽ gobble lên value nếu có thể. Từ việc đọc các câu hỏi và tài liệu tương tự khác, tôi đã tập hợp rằng tôi cần quản lý lookahead đó với NotAny hoặc FollowedBy, nhưng tôi đã không thể tìm ra cách để thực hiện công việc đó.

+0

Không thể bạn chỉ cần thực hiện một danh sách rõ ràng của khả năng các nhà khai thác? –

+0

@KarlKnechtel Thật không may, danh sách các nhà khai thác sẽ được mở rộng. Tôi đoán, tôi có thể biên dịch danh sách đó vào thời gian chạy và xây dựng ngữ pháp một cách năng động, nhưng có vẻ như nó sẽ sạch hơn để có thể làm cho trình phân tích cú pháp trở nên bất khả tri. Đó là một kế hoạch sao lưu tốt, mặc dù, trong trường hợp tôi không thể làm việc nó ra, vì vậy cảm ơn. –

Trả lời

11

Đây là nơi tốt để trở thành Người phân tích cú pháp. Hay chính xác hơn, làm cho trình phân tích cú pháp suy nghĩ giống như bạn làm. Hãy tự hỏi, "Trong" tác giả là shakespeare ', làm thế nào để tôi biết rằng' shakespeare 'không phải là một phần của nhà điều hành? " Bạn biết rằng 'shakespeare' là giá trị bởi vì nó nằm ở cuối truy vấn, không có gì hơn sau nó. Vì vậy, các từ của nhà điều hành không chỉ là các từ của alphas, chúng là các từ của các chữ cái không được theo sau bởi phần cuối của chuỗi. Bây giờ xây dựng rằng logic lookahead vào định nghĩa của bạn về operator:

operator = OneOrMore(Word(alphas) + ~FollowedBy(StringEnd())) 

Và tôi nghĩ rằng đây sẽ bắt đầu phân tích tốt hơn cho bạn.

Một số lời khuyên khác:

  • tôi chỉ sử dụng '^' điều hành nếu có sẽ có một số sự mơ hồ càng tốt, như thế nào nếu tôi sẽ phân tích một chuỗi với số đó có thể là số nguyên hoặc hex. Nếu tôi đã sử dụng Word(nums) | Word(hexnums), thì tôi có thể xử lý sai "123ABC" chỉ là "123" hàng đầu. Bằng cách thay đổi '|' đến '^', tất cả các lựa chọn thay thế sẽ được kiểm tra và trận đấu dài nhất được chọn. Trong ví dụ về phân tích cú pháp số thập phân hoặc số nguyên hex, tôi có thể nhận được kết quả tương tự bằng cách đảo ngược các lựa chọn thay thế và kiểm tra trước tiên cho Word(hexnums). Trong ngôn ngữ truy vấn của bạn, không có cách nào để nhầm lẫn chuỗi được trích dẫn với giá trị từ đơn không được trích dẫn (một dẫn với ' hoặc ", giá trị kia không), vì vậy không có lý do gì để sử dụng '^', '| ' sẽ đủ. Tương tự cho value = singleValue^listValue.

  • Thêm tên kết quả cho các thành phần quan trọng của chuỗi truy vấn của bạn sẽ làm cho nó dễ dàng hơn để làm việc với sau:

    clause = fieldname("fieldname") + originalTextFor(operator)("operator") + value("value")

    Bây giờ bạn có thể truy cập các giá trị phân tích cú pháp theo tên thay vì bởi vị trí phân tích cú pháp (mà sẽ nhận được khó khăn và dễ bị lỗi khi bạn bắt đầu trở nên phức tạp hơn với các lĩnh vực bắt buộc và như vậy):

    queryParts = clause.parseString('author is william')

    print queryParts.fieldname

    print queryParts.operator

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