2012-05-04 3 views
5

У меня есть следующее Подвыражение разобрать «цитирует», которые имеют следующий форматРекомендации по FParsec для обработки пробельных

"5.75 @ 5.95" 

поэтому у меня есть это парсеки выражения для синтаксического анализа его

let pquote x = (sepBy (pfloat) ((spaces .>> (pchar '/' <|> pchar '@')>>. spaces))) x 

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

let pquote x = (sepBy (pfloat) (attempt (spaces .>> (pchar '/' <|> pchar '@')>>. spaces))) x 

Как я не знаю fparsec так хорошо, интересно, есть ли лучший способ написать это. это кажется немного тяжелым (в то же время очень управляемым конечно)

ответ

6
let s1 = "5.75   @    5.95    " 
let s2 = "5.75/5.95 " 
let pquote: Parser<_> = 
    pfloat 
    .>> spaces .>> skipAnyOf ['@'; '/'] .>> spaces 
    .>>. pfloat 
    .>> spaces 

Примечание:

  1. Я сделал spaces опциональный везде spaces пропускает любую последовательность нулевой или более пробелов, так что нет никакой необходимости использовать opt - спасибо @Daniel;
  2. type Parser<'t> = Parser<'t, UserState> - Я определяю его таким образом, чтобы избежать ошибки «ограничения значения»; вы можете удалить его;
  3. Кроме того, не стоит забывать следующее, если ваша программа может работать в системе с языковые настройки по умолчанию, имеющих десятичную запятую: System.Threading.Thread.CurrentThread.CurrentCulture <- Globalization.CultureInfo.GetCultureInfo "en-US" это не будет работать, спасибо @Stephan
  4. я бы не использовать sepBy, если у меня нет список значений неизвестного размера.
  5. Если вам действительно не нужно возвращаемое значение (например, '@' символов), рекомендуется использовать функции skip* вместо p* для соображений производительности.

UPD добавлен слэш в качестве разделителя

+0

это # ​​2 была боль. хороший трюк, чтобы знать. все полезные комментарии .. – nicolas

+0

ваш проект сумасшедший. ты сумасшедший. Приятно видеть, что какой-то парсек используется здесь, показания качества, я думаю. – nicolas

+1

['spaces'] (http://www.quanttec.com/fparsec/reference/charparsers.html#members.spaces) анализирует нулевые или более пробелы - не нужно использовать' opt'. – Daniel

3

я бы, вероятно, сделать что-то вроде этого, который возвращает float * float:

let ws = spaces 
let quantity = pfloat .>> ws 
let price = pfloat .>> ws 
let quoteSep = pstring "@" .>> ws 
let quote = quantity .>> quoteSep .>>. price //`.>> eof` (if final parser) 

Это типично для каждого синтаксического анализа потреблять конечные пробелы. Просто убедитесь, что ваш парсер верхнего уровня включает eof.

1

Предполагая, что вы могли бы иметь более двух float во входном потоке и «/» и «@» являются разделители:

let ws = spaces 
let str_ws s = pstring s .>> ws 
let float_ws = pfloat .>> ws 
let pquote = sepBy float_ws (str_ws "/" <|> str_ws "@") 

Говоря об обработке непечатаемых, this section в FParsec учебник действительно полезно.