Я нашел эту полезную статью об использовании активных шаблонов с регулярными выражениями: 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 [ for g in 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.Success) |> 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);]
В основном сопоставление каждого найденного уникального совпадения с последующим подсчетом количества раз, когда определенная совпадающая строка была найдена в тексте.
Если вы думаете, что я иду по неправильному пути, пожалуйста, не стесняйтесь предлагать совершенно другой подход. Я несколько новичок как с активными шаблонами, так и с регулярными выражениями, поэтому я понятия не имею, где даже начать пытаться исправить это.
Я также придумал это, что в основном я бы сделал в С#, переведенном в 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<string,int>()
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 matches : Dictionary = dict [("http://www.bob.com", 2); ("http://www.b.com", 1); ("http://www.bill.com", 1)]
В основном это результат, который я ищу, но я пытаюсь изучить функциональный способ сделать это, и я думаю, что это должно включать активные шаблоны. Не стесняйтесь пытаться "функционализировать" это, если это имеет больше смысла, чем моя первая попытка.
Спасибо заранее,
Боб