2009-06-17 35 views
6

cách tốt nhất để sử dụng biểu thức thông thường với các tùy chọn (cờ) trong Haskellbiểu thức thông thường case-insensitive

gì tôi sử dụng

Text.Regex.PCRE 

Các tài liệu liệt kê một vài lựa chọn thú vị như compCaseless, compUTF8, .. Nhưng tôi không biết cách sử dụng chúng với (= ~)

Trả lời

16

Tất cả các Text.Regex.* module sử dụng nhiều của typeclasses, đó là có cho khả năng mở rộng và "quá tải" hành vi giống như, nhưng làm cho việc sử dụng ít obvio chúng tôi chỉ nhìn thấy các loại.

Bây giờ, có thể bạn đã bắt đầu từ trình kết hợp cơ bản =~.

(=~) :: 
    (RegexMaker Regex CompOption ExecOption source 
    , RegexContext Regex source1 target) 
    => source1 -> source -> target 
(=~~) :: 
    (RegexMaker Regex CompOption ExecOption source 
    , RegexContext Regex source1 target, Monad m) 
    => source1 -> source -> m target 

Để sử dụng =~, thì phải có một thể hiện của RegexMaker ... cho LHS, và RegexContext ... cho RHS và kết quả.

class RegexOptions regex compOpt execOpt | ... 
     | regex -> compOpt execOpt 
     , compOpt -> regex execOpt 
     , execOpt -> regex compOpt 
class RegexOptions regex compOpt execOpt 
     => RegexMaker regex compOpt execOpt source 
     | regex -> compOpt execOpt 
     , compOpt -> regex execOpt 
     , execOpt -> regex compOpt 
    where 
    makeRegex :: source -> regex 
    makeRegexOpts :: compOpt -> execOpt -> source -> regex 

Một thể hiện giá trị của tất cả các lớp này (ví dụ, regex=Regex, compOpt=CompOption, execOpt=ExecOptionsource=String) có nghĩa là nó có thể biên dịch một regex với compOpt,execOpt tùy chọn từ một số hình thức source. (Ngoài ra, đưa ra một số regex loại, có đúng một compOpt,execOpt bộ mà đi cùng với nó. Rất nhiều source loại khác nhau là okay, mặc dù.)

class Extract source 
class Extract source 
     => RegexLike regex source 
class RegexLike regex source 
     => RegexContext regex source target 
    where 
    match :: regex -> source -> target 
    matchM :: Monad m => regex -> source -> m target 

Một thể hiện giá trị của tất cả các lớp này (ví dụ, regex=Regex , source=String, target=Bool) có nghĩa là có thể khớp với một số sourceregex để mang lại một số target. (Khác hợp lệ target s cho những cụ regexsourceInt, MatchResult String, MatchArray, vv)

Đặt này lại với nhau và nó khá rõ ràng rằng =~=~~ chỉ đơn giản là chức năng thuận tiện

source1 =~ source 
    = match (makeRegex source) source1 
source1 =~~ source 
    = matchM (makeRegex source) source1 

và cũng là =~=~~ không có chỗ để chuyển các tùy chọn khác nhau tới makeRegexOpts.

Bạn có thể làm của riêng

(=~+) :: 
    (RegexMaker regex compOpt execOpt source 
    , RegexContext regex source1 target) 
    => source1 -> (source, compOpt, execOpt) -> target 
source1 =~+ (source, compOpt, execOpt) 
    = match (makeRegexOpts compOpt execOpt source) source1 
(=~~+) :: 
    (RegexMaker regex compOpt execOpt source 
    , RegexContext regex source1 target, Monad m) 
    => source1 -> (source, compOpt, execOpt) -> m target 
source1 =~~+ (source, compOpt, execOpt) 
    = matchM (makeRegexOpts compOpt execOpt source) source1 

mà có thể được sử dụng như

"string" =~+ ("regex", CompCaseless + compUTF8, execBlank) :: Bool 

hoặc ghi đè =~=~~ với các phương pháp có thể chấp nhận tùy chọn

import Text.Regex.PCRE hiding ((=~), (=~~)) 

class RegexSourceLike regex source 
    where 
    makeRegexWith source :: source -> regex 
instance RegexMaker regex compOpt execOpt source 
     => RegexSourceLike regex source 
    where 
    makeRegexWith = makeRegex 
instance RegexMaker regex compOpt execOpt source 
     => RegexSourceLike regex (source, compOpt, execOpt) 
    where 
    makeRegexWith (source, compOpt, execOpt) 
     = makeRegexOpts compOpt execOpt source 

source1 =~ source 
    = match (makeRegexWith source) source1 
source1 =~~ source 
    = matchM (makeRegexWith source) source1 

hoặc bạn chỉ có thể sử dụng match, makeRegexOpts, v.v. trực tiếp khi cần.

+0

Ah, có vẻ như tôi đã bị đánh bại với giải pháp. Đó là những gì tôi nhận được để viết tất cả các loại công cụ không cần thiết: -/ – ephemient

+0

Ah, tôi cảm thấy một chút tội lỗi bây giờ, bạn chắc chắn cung cấp một cái nhìn tổng quan hơn toàn diện! Tôi thích bạn gợi ý cho (= ~ +) bằng cách này. – dukedave

+0

đó là một câu trả lời rất đầy đủ và toàn diện thực sự, tôi muốn thưởng cho những nỗ lực, nhưng tôi không biết nếu đó là thực tế phổ biến để chuyển "câu trả lời được chấp nhận"? dù sao, tôi mới đến Haskell, và câu trả lời này thực sự đã giúp tôi hiểu một số nguyên tắc thông minh của ngôn ngữ (cũng có ít lỗi đánh máy lúc đầu bạn viết = ~ thay vì = ~~) –

7

Tôi không biết gì về Haskell, nhưng nếu bạn đang sử dụng thư viện regex dựa trên PCRE, thì bạn có thể sử dụng công cụ sửa đổi chế độ bên trong biểu thức chính quy. Để phù hợp với "caseless" trong một trường hợp thời trang không nhạy cảm, bạn có thể sử dụng regex này trong PCRE: (? I)

(?i)caseless 

Các sửa đổi chế độ ghi đè bất kỳ nhạy trường hợp hoặc trường hợp tùy chọn vô cảm đó đã được thiết lập bên ngoài biểu thức chính quy. Nó cũng làm việc với các toán tử không cho phép bạn đặt bất kỳ tùy chọn nào.

Tương tự, (? S) bật "chế độ dòng đơn", làm cho dấu ngắt dòng khớp, (? M) bật "chế độ nhiều dòng" làm cho^và $ khớp ở ngắt dòng và (? X) bật chế độ khoảng cách tự do (không gian thoát và ngắt dòng bên ngoài các lớp ký tự là không đáng kể). Bạn có thể kết hợp các chữ cái. (? ismx) bật mọi thứ. Một dấu gạch nối tắt tùy chọn. (? -i) làm cho trường hợp regex nhạy cảm. (? x-i) bắt đầu một regex nhạy cảm với khoảng trắng.

+0

cũng hoạt động! nó đơn giản hơn nhiều nhưng cũng ít chung chung hơn giải pháp được chấp nhận –

+0

+1 Điều này cho phép chúng ta giữ toán tử '= ~' không chính thức và làm cho regex được định nghĩa là một 'Chuỗi'. Cơ bản hơn nhiều! –

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