Dla zabawy, oto zarys tego, jak analizować łańcuchy przy użyciu FParsec, biblioteki kombinatorowej parsera.
Po pierwsze, trzeba importować kilka modułów:
open FParsec.Primitives
open FParsec.CharParsers
Następnie można zdefiniować parser, który będzie pasował wszystkie ciągi zamknięte w nawiasach:
let betweenParentheses p s = between (pstring "(") (pstring ")") p s
To będzie pasował dowolny ciąg znaków w nawiasach, takie jak "(42)"
, "(foo)"
, "(1,2,3,4,5)"
itd., w zależności od określonego parsera p
przekazanego jako pierwszy argument.
W celu analizowania numery jak "(1,2,3,4,5)"
lub "(1,2)"
, można połączyć betweenParentheses
z FParsec wbudowanej sepBy
i pint32
:
let pnumbers s = betweenParentheses (sepBy pint32 (pstring ",")) s
pint32
jest parser liczb całkowitych i sepBy
jest parser, który odczytuje listę wartości, oddzielone ciągiem znaków - w tym przypadku ","
.
W celu analizowania całego „grupa” wartości, takie jak "(states, (1,2,3,4,5))"
lub "(alpha, (1,2))"
, można ponownie użyć betweenParentheses
i pnumbers
:
let pgroup s =
betweenParentheses
(manyTill anyChar (pstring ",") >>. spaces >>. pnumbers) s
Połączenie manyTill
analizuje każdą wartość char
aż napotka ,
. Następnie parser pgroup
oczekuje dowolnej liczby spacji, a następnie formatu zdefiniowanego przez pnumbers
.
Wreszcie, można zdefiniować funkcję, która uruchamia pgroup
parser na sznurku:
// string -> int32 list option
let parseGroup s =
match run pgroup s with
| Success (result, _, _) -> Some result
| Failure _ -> None
Ponieważ ta funkcja zwraca opcję można wykorzystać List.choose
mapować struny, które mogą być analizowane:
> ["(states, (1,2,3,4,5))"; "(alpha, (1,2))"; "(final, (1))"]
|> List.choose parseGroup;;
val it : int32 list list = [[1; 2; 3; 4; 5]; [1; 2]; [1]]
Używanie FParsec jest najprawdopodobniej przesadą, chyba że masz bardziej elastyczne reguły formatowania niż te, które można łatwo rozwiązać za pomocą standardowego interfejsu API .NET string
.
Najpierw podziel problem na poszczególne elementy listy. Zacznij od wyodrębnienia listy liczb całkowitych z ciągu znaków w tym formacie (czy mogę zaproponować wyrażenia regularne). Od tego momentu jest to tylko kwestia mapowania tego przez każdy ciąg na liście (List.map). – Jwosty