F # Сопоставление совпадений регулярных выражений с активными шаблонами

Я нашел эту полезную статью об использовании активных шаблонов с регулярными выражениями: http://www.markhneedham.com/blog/2009/05/10/f-regular-expressionsactive-patterns/

Исходный фрагмент кода, использованный в статье, был следующим:

open System.Text.RegularExpressions

let (|Match|_|) pattern input =
    let m = Regex.Match(input, pattern) in
    if m.Success then Some (List.tl [ for g in m.Groups -> g.Value ]) else None

let ContainsUrl value = 
    match value with
        | Match "(http:\/\/\S+)" result -> Some(result.Head)
        | _ -> None

Что позволит вам знать, был ли найден хотя бы один URL и что это за URL (если я правильно понял фрагмент)

Затем в разделе комментариев Джоэл предложил эту модификацию:

Альтернатива, поскольку данная группа может или совпадение может быть неудачным:

 List.tail [для g в m.Groups -> if g.Success then Some g.Value else None]

Или вы даете ярлыки своим группы, и вы хотите получить к ним доступ имя:

 (re.GetGroupNames ()
 |> Seq.map (fun n -> (n, m.Groups. [N]))
 |> Seq.filter (fun (n, g) -> g. Успех)
 |> Seq.map (fun (n, g) -> (n, g.Value))
 |> Map.ofSeq)

Попытавшись объединить все это, я получил следующий код:

let testString = "http://www.bob.com http://www.b.com http://www.bob.com http://www.bill.com"

let (|Match|_|) pattern input =
    let re = new Regex(pattern)
    let m = re.Match(input) in
    if m.Success then Some ((re.GetGroupNames()
                                |> Seq.map (fun n -> (n, m.Groups.[n]))
                                |> Seq.filter (fun (n, g) -> g.Success)
                                |> Seq.map (fun (n, g) -> (n, g.Value))
                                |> Map.ofSeq)) else None

let GroupMatches stringToSearch = 
    match stringToSearch with
        | Match "(http:\/\/\S+)" result -> printfn "%A" result
        | _ -> ()


GroupMatches testString;;

Когда я запускаю свой код в интерактивном сеансе, на выходе получается следующее:

 map [("0", "http: / /www.bob.com "); ("1", "http://www.bob.com")]

Результат, которого я пытаюсь достичь, будет выглядеть примерно так:

 map [("http://www.bob.com", 2); ("http://www.b.com", 1); ("http://www.bill.com", 1);]

Обычно отображение каждого найденного уникального совпадения с последующим подсчетом количества раз, когда в тексте была найдена конкретная соответствующая строка.

Если вы думаете, что я иду по неправильному пути, пожалуйста, не стесняйтесь предложить совершенно другой подход. Я новичок как в активных шаблонах, так и в регулярных выражениях, поэтому я понятия не имею, с чего начать, пытаясь это исправить.

Я также придумал это, что в основном то, что я делал бы в C #, переведенном на F #.

let testString = "http://www.bob.com http://www.b.com http://www.bob.com http://www.bill.com"

let matches =
    let matchDictionary = new Dictionary()
    for mtch in (Regex.Matches(testString, "(http:\/\/\S+)")) do
        for m in mtch.Captures do
            if(matchDictionary.ContainsKey(m.Value)) then
                matchDictionary.Item(m.Value) <- matchDictionary.Item(m.Value) + 1
            else
                matchDictionary.Add(m.Value, 1)
    matchDictionary

Что возвращает это при запуске:

 val соответствует: Dictionary = dict [("http://www.bob.com", 2); ("http://www.b.com", 1); ("http://www.bill.com", 1)]

Это в основном результат, который я ищу, но я пытаюсь изучить функциональный способ сделать это, и я думаю, что он должен включать активные шаблоны. Не стесняйтесь попробовать "функционализировать" это, если это имеет больше смысла, чем моя первая попытка.

Заранее спасибо,

Боб

19
задан ildjarn 16 April 2011 в 03:24
поделиться