2010-09-20 12 views
5

Ben alıntı ise şöyle benzer, Fsharp kullanarak bir dize orta kısmını ayıklamak istiyorum:FSharp'ta bir dizenin orta kısmını nasıl çıkarabilirim?

let middle = 
    match original with 
    | "\"" + mid + "\"" -> mid 
    | all -> all 

Ama bunun nedeni infix operatörünün + desen ifadesinde çalışmaz. Bunu nasıl çıkarabilirim?

+0

(http://stackoverflow.com/questions/3722591/pattern-matching-on-the-beginning- adresindeki alıntı metninin ilk örneği of-a-string-in-f – Brian

cevap

10

Bunun için doğrudan bir destek olduğunu sanmıyorum, ancak kesinlikle etkin model yazabilirsiniz. Aktif kalıplar, desen eşlemesinin bir parçası olarak çalışacak kendi kodunuzu uygulamanıza olanak tanır ve & değerini değerin bir kısmını geri getirebilirsiniz.

Aşağıda, iki parametre (önek ve postfix dizesi) alan ve belirtilen giriş belirtilen dizelerle başlayıp bitip bitmediğinde başarılı olan bir kalıptır. desen (başarısız olabilir) tam değildir, bu yüzden |Name|_| sözdizimi kullanacağız ve opsiyon değeri döndürmek gerekir:

let (|Middle|_|) prefix postfix (input:string) = 
    // Check if the string starts with 'prefix', ends with 'postfix' and 
    // is longer than the two (meaning that it contains some middle part) 
    if input.StartsWith(prefix) && input.EndsWith(postfix) && 
    input.Length >= (prefix.Length + postfix.Length) then 
    // Strip the prefix/postfix and return 'Some' to indicate success 
    let len = input.Length - prefix.Length - postfix.Length 
    Some(input.Substring(prefix.Length, len)) 
    else None // Return 'None' - string doesn't match the pattern 

Şimdi eşleşen desende Middle kullanabilirsiniz (örn match kullanılırken):

match "[aaa]" with 
| Middle "[" "]" mid -> mid 
| all -> all 
+0

Uygulama stratejiniz benimkinden daha iyidir (yalnızca Substring'e bir çağrı), ancak aynı fikri gördüğümüze sevindim! :) – Brian

+0

Teşekkürler Tomas. Cevabınız çok açık ve yardımsever. Brian ve kvb'ye de teşekkürler. Maalesef, StackOverflow'ta yeniyim ve cevaplarınızı yükseltmek için yeterli krediniz yok. – newwave

+0

@Brian: Evet, neredeyse aynı cevabı yayınladık gibi görünüyor! Ben de stratejinizi düşündüm (ancak kontrol uzunluğunun daha kolay olduğunu düşündüm) ve ayrıca bir tuple :-) kullanarak iki argümanı geçmeyi düşündüm de –

2

Kalıpların sınırlı bir dilbilgisi vardır - yalnızca herhangi bir deyimi kullanamazsınız. Bu durumda, sadece bir kullanmayı tercih ediyorum/sonra/else if:

let middle (s:string) = 
    if s.[0] = '"' && s.[s.Length - 1] = '"' && s.Length >= 2 then 
    s.Substring(1,s.Length - 2) 
    else s 

statik bilinen başlangıçlar ve sonlar ile bir dize ortasına kapma sonra yapabilirsinizEND_SPAN, bir sürü yapacağız bir şey ise Tomas'ın önerdiği gibi aktif bir model kullanın.

+0

Teşekkürler kvb. Tomas'ın cevabını sadece zorunlu olarak kullanmak istemediğim için tercih ediyorum. – newwave

3

Parametre için active patterns kurtarmaya!

let (|HasPrefixSuffix|_|) (pre:string, suf:string) (s:string) = 
    if s.StartsWith(pre) then 
     let rest = s.Substring(pre.Length) 
     if rest.EndsWith(suf) then 
      Some(rest.Substring(0, rest.Length - suf.Length)) 
     else 
      None 
    else 
     None 

let Test s = 
    match s with 
    | HasPrefixSuffix("\"","\"") inside -> 
     printfn "quoted, inside is: %s" inside 
    | _ -> printfn "not quoted: %s" s 

Test "\"Wow!\"" 
Test "boring" 
+1

Parametreli aktif desenler inanılmaz derecede güçlüdür. – gradbot

+0

Cidden nifty! :-) –

2

... ya da sadece kullanmak düz eski düzenli ifade

let Middle input = 
    let capture = Regex.Match(input, "\"([^\"]+)\"") 
    match capture.Groups.Count with 
    | 2 -> capture.Groups.[1].Value 
    | _ -> input 
+0

Bir seçenek türü döndürmek daha iyi olabilir? –

+0

Yazar, anladığı gibi, tüm dizeyi geri döndürmek istiyor. –

0

bunun ne kadar etkili değil emin:

let GetQuote (s:String) (q:char) = 
     s 
     |> Seq.skip ((s |> Seq.findIndex (fun c -> c = q))+1) 
     |> Seq.takeWhile (fun c-> c <> q) 
     |> Seq.fold(fun acc c -> String.Format("{0}{1}", acc, c)) "" 

Veya kat yerine alt dize ile bu var:

let GetQuote2 (s:String) (q:char) = 
    let isQuote = (fun c -> c = q) 
    let a = (s |> Seq.findIndex isQuote)+1 
    let b = ((s |> Seq.take(a) |> Seq.findIndex isQuote)-1) 
    s.Substring(a,b); 

Bunlar alacak "Hello [Dünya]" -> "Dünya" (

)
İlgili konular