2016-07-18 4 views
2

F #의 사용법에 대한 정규식 구현에 만족하지 않으므로 정규식 체인을 구현하고 싶습니다. 기본적으로 다음과 같이 작동합니다 :F # Regex matching chain

주어진 문자열이 첫 번째 패턴과 일치하는지 여부를 확인합니다. s. 그럴 경우 첫 번째 패턴과 관련된 기능을 실행해야합니다. 그렇지 않으면 다음 단계로 계속 진행해야합니다.

let RegexMatch ((s : string, c : bool), p : string, f : GroupCollection -> unit) = 
    if c then 
     let m = Regex.Match(s, p) 
     if m.Success then 
      f m.Groups 
      (s, false) 
     else (s, c) 
    else (s, c) 


("my input text", true) 
|> RegexMatch("pattern1", fun g -> ...) 
|> RegexMatch("pattern2", fun g -> ...) 
|> RegexMatch("pattern3", fun g -> ...) 
|> .... // more patterns 
|> ignore 

문제는 앞으로 파이프 연산자는 파이프 튜플하지 않는 것 또는 내 구현 '디자인'을 좋아하지 않기 때문에이 코드가 잘못되었다고이다 다음과 같이

나는 그것을 구현하는 시도 .

내 질문 : 위의 코드를 쉽게 수정할 수 있습니까? 아니면 다른 종류의 정규식 체인을 구현해야합니까?

+2

"*으로 나는 F #의 정규 표현식 구현에 완전히 만족하지 않습니다. * "F #에는 정규 표현식 구현이 없습니다. .NET에서는 .NET Core가 수행하지만 Mono는 그렇지만 F #은 정규식이 무엇인지 전혀 인식하지 못합니다. – ildjarn

+0

또 다른 접근 방법은 데이터 지향적 인 방법입니다 : 정규 표현식 - 함수 쌍을리스트에 넣고'List.tryPick'을 사용하여 첫 번째로 일치하는 정규 표현식에 대한 함수를 실행합니다. 이것은 regex-function case를 동적으로 구축 할 수 있도록 해줍니다. – TheQuickBrownFox

답변

1

제게는 구현하려는 내용이 Active Patterns 인 것처럼 들립니다.활성 패턴을 사용하여

당신은 정규식 패턴에 일치 구문 일치 규칙적인 패턴을 사용할 수 있습니다

let (|RegEx|_|) p i = 
    let m = System.Text.RegularExpressions.Regex.Match (i, p) 
    if m.Success then 
    Some m.Groups 
    else 
    None 

[<EntryPoint>] 
let main argv = 
    let text = "123" 
    match text with 
    | RegEx @"\d+" g -> printfn "Digit: %A" g 
    | RegEx @"\w+" g -> printfn "Word : %A" g 
    | _    -> printfn "Not recognized" 
    0 

또 다른 방법은 표도르는 철도가 지향으로 프로그래밍을 의미한다 무엇을 사용하는 것입니다

type RegexResult<'T> = 
    | Found  of 'T 
    | Searching of string 

let lift p f = function 
    | Found v  -> Found v 
    | Searching i -> 
    let m = System.Text.RegularExpressions.Regex.Match (i, p) 
    if m.Success then 
     m.Groups |> f |> Found 
    else 
     Searching i 

[<EntryPoint>] 
let main argv = 
    Searching "123" 
    |> lift @"\d+" (fun g -> printfn "Digit: %A" g) 
    |> lift @"\w+" (fun g -> printfn "Word : %A" g) 
    |> ignore 
    0 
6

기능이 RegexMatch은 튜플 매개 변수가 있으므로 파이핑을 지원하지 않습니다.

("text", true) 
|> RegexMatch("pattern", fun x -> ...) 

여기에 해당 될 것이다 : 하나는이 표현이 있음을 분명히 알 수 있습니다,이에서

let (|>) x f = f x 

:

첫째, 파이프의 정의를 보면

RegexMatch("pattern", fun x -> ...) ("text", true) 

기능 서명과 일치합니까? 당연히 아니. 서명에서 text/bool 쌍이 먼저 나오고 패턴과 함수와 함께 매개 변수의 세 부분에 속합니다. AS를

("input", true) 
|> RegexMatch "pattern1" (fun x -> ...) 
|> RegexMatch "pattern2" (fun x -> ...) 
|> RegexMatch "pattern3" (fun x -> ...) 

:

let RegexMatch p f (s, c) = ... 

는 그런 다음 배관을 수행 할 수 있습니다

당신이를 취할 필요가 작동하려면 카레 형태의 매개 변수와 마지막을 "파이프" 제쳐두고, 저는 여러분의 접근 방식이 매우 어리석지 않다는 것을 알아야합니다. 입니다. 전체 로직을 부작용에 기초하고 있기 때문에 프로그램을 구성 할 수없고 테스트하기가 어렵고 버그가 발생하기 쉽습니다. F #의 이점을 효과적으로 활용하지 못하고 효과적으로 "C# with nicer syntax"를 사용합니다.

또한 실제로 원하는 결과를 얻기 위해 실제로 연구 된 방법이 있습니다. 하나는 Railway-oriented programming (모나드 계산이라고도 함)을 확인하십시오.