Я нашел эту полезную статью об использовании активных шаблонов с регулярными выражениями: 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)]
Это в основном результат, который я ищу, но я пытаюсь изучить функциональный способ сделать это, и я думаю, что он должен включать активные шаблоны. Не стесняйтесь попробовать "функционализировать" это, если это имеет больше смысла, чем моя первая попытка.
Заранее спасибо,
Боб