2012-10-17 26 views
14

Tôi đang viết chương trình đầu tiên của mình với Parsec. Tôi muốn phân tích các lược đồ MySQL và muốn tìm ra cách tốt nhất để phân tích các chuỗi đại diện cho các từ khóa nhất định trong trường hợp không phân biệt chữ hoa chữ thường. Dưới đây là một số mã cho thấy cách tiếp cận tôi đang sử dụng để phân tích cú pháp "TẠO" hoặc "tạo". Có cách nào tốt hơn để làm điều này? Một câu trả lời mà không phải để xây dựngExpressionParser sẽ là tốt nhất. Tôi đang đi các bước em bé ở đây.Cách nào tốt nhất để phân tích cú pháp phân biệt chữ hoa chữ thường với Text.Combinators.Parsec?

p_create_t :: GenParser Char st Statement 
    p_create_t = do 
     x <- (string "CREATE" <|> string "create") 
     xs <- manyTill anyChar (char ';') 
     return $ CreateTable (x ++ xs) [] -- refine later 
+5

Tôi giả định rằng 'map toLower' trên đầu vào trước khi thậm chí chạy trình phân tích cú pháp không phải là một tùy chọn? Ngoài ra, tôi mong đợi "phân biệt chữ hoa chữ thường" cũng khớp với "Tạo", "CrEaTe", "TẠO" hoặc bất kỳ biến thể nào khác mà ví dụ của bạn từ chối. Bạn muốn cái nào –

+0

Điều đó có hiệu quả. Cảm ơn. Tôi đã không nghĩ về điều đó! – dan

+1

@dan Hãy cẩn thận nếu đầu vào của bạn chứa chuỗi, chúng cũng sẽ được hạ thấp hơn. Ví dụ: nếu bất kỳ cột nào của bạn chứa giá trị chuỗi mặc định. –

Trả lời

17

Bạn có thể tạo trình phân tích cú pháp phân biệt chữ hoa chữ thường.

-- Match the lowercase or uppercase form of 'c' 
caseInsensitiveChar c = char (toLower c) <|> char (toUpper c) 

-- Match the string 's', accepting either lowercase or uppercase form of each character 
caseInsensitiveString s = try (mapM caseInsensitiveChar s) <?> "\"" ++ s ++ "\"" 
8

Lặp đi lặp lại những gì tôi đã nói trong một chú thích, như nó đã được rõ ràng hữu ích:

Giải pháp búa tạ đơn giản ở đây là để chỉ đơn giản là bản đồ toLower trên toàn bộ đầu vào trước khi chạy phân tích cú pháp, sau đó làm tất cả phù hợp với từ khóa của bạn trong chữ thường.

Điều này thể hiện những khó khăn rõ ràng nếu bạn đang phân tích cú pháp một số thứ cần phân biệt chữ hoa chữ thường ở một số nơi và phân biệt chữ hoa chữ thường, hoặc nếu bạn quan tâm đến việc bảo quản trường hợp vì lý do thẩm mỹ. Ví dụ: mặc dù các thẻ HTML phân biệt chữ hoa chữ thường, nhưng việc chuyển đổi toàn bộ trang web thành chữ thường trong khi phân tích cú pháp có thể là không mong muốn. Ngay cả khi biên dịch một ngôn ngữ lập trình không phân biệt chữ hoa chữ thường, các mã định danh chuyển đổi có thể gây phiền toái, vì bất kỳ thông báo lỗi kết quả nào cũng không khớp với những gì người lập trình viết.

0

Thay vì lập bản đồ toàn đầu vào với toLower, xem xét sử dụng caseString từ Text.ParserCombinators.Parsec.Rfc2234 (từ gói hsemail)

Text.ParsecCombinators.Parsec.Rfc2234

p_create_t :: GenParser Char st Statement 
p_create_t = do 
    x <- (caseString "create") 
    xs <- manyTill anyChar (char ';') 
    return $ CreateTable (x ++ xs) [] -- refine later 

Bây giờ x sẽ là bất cứ trường hợp biến hiện diện trong đầu vào mà không thay đổi đầu vào của bạn.

ps: Tôi biết rằng đây là một câu hỏi cổ xưa, tôi chỉ nghĩ rằng tôi sẽ thêm này như câu hỏi này đã đưa ra trong khi tôi đang tìm kiếm một vấn đề tương tự

+0

Đây không phải là từ Text.ParsecCombinators.Parsec. Nó là từ Text.ParsecCombinators.Parsec.Rfc2234. Liên kết của bạn là chính xác, nhưng tiêu đề của bạn là sai. Cũng cần lưu ý rằng đó là một phần của gói hsemail, mà ai đó có thể chưa cài đặt. – Sean

2

Không, Parsec không thể làm điều đó theo cách sạch. string được triển khai trên đầu trang của bộ phối hợp nguyên thủy tokens được mã hóa cứng để sử dụng kiểm tra bình đẳng (==). Việc phân tích ký tự phân biệt chữ hoa chữ thường đơn giản hơn một chút, nhưng bạn có thể muốn nhiều hơn.

Tuy nhiên có một ngã ba hiện đại của Parsec, gọi Megaparsec trong đó có giải pháp tích hợp cho tất cả mọi thứ bạn có thể muốn:

λ> parseTest (char' 'a') "b" 
parse error at line 1, column 1: 
unexpected 'b' 
expecting 'A' or 'a' 
λ> parseTest (string' "foo") "Foo" 
"Foo" 
λ> parseTest (string' "foo") "FOO" 
"FOO" 
λ> parseTest (string' "foo") "fo!" 
parse error at line 1, column 1: 
unexpected "fo!" 
expecting "foo" 

Lưu ý thông báo lỗi cuối cùng, đó là tốt hơn so với những gì bạn có thể nhận được phân tích cú pháp từng ký tự một (đặc biệt hữu ích trong trường hợp cụ thể của bạn). string' được triển khai giống như số string của Parsec nhưng sử dụng so sánh trường hợp không phân biệt chữ hoa chữ thường để so sánh các ký tự. Ngoài ra còn có oneOf'noneOf' rằng có thể hữu ích trong một số trường hợp.


Tiết lộ: Tôi là một trong các tác giả của Megaparsec.

+0

Thật sự đáng ngạc nhiên khi 'mã thông báo' không cho phép một hàm so sánh được truyền cho nó để thực hiện so sánh trong Parsec gốc. – MicroVirus

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