String F#如何使用字符串输入解析和计算计算器表达式
我必须用F#来创建一个计算器,而我正忙于一项任务 我需要将一个和作为字符串传入控制台,例如“4+5”,然后解析和计算它 有什么想法吗 任何帮助都将不胜感激String F#如何使用字符串输入解析和计算计算器表达式,string,parsing,f#,calculator,f#-interactive,String,Parsing,F#,Calculator,F# Interactive,我必须用F#来创建一个计算器,而我正忙于一项任务 我需要将一个和作为字符串传入控制台,例如“4+5”,然后解析和计算它 有什么想法吗 任何帮助都将不胜感激 open System let rec calculator() = printf "Choose a sum type \n1: Addition\n2: Subtraction\n3: Mulitiplication\n4: Division\n\n\n" let input = Console.ReadLine();
open System
let rec calculator() =
printf "Choose a sum type \n1: Addition\n2: Subtraction\n3: Mulitiplication\n4: Division\n\n\n"
let input = Console.ReadLine();
printf "now type in 2 numbers\n"
let num1 = Console.ReadLine();
let num2 = Console.ReadLine();
let a : int = int32 num1
let b : int = int32 num2
let addition x y = x + y
let subtraction x y = x - y
let multiply x y = x * y
let divide x y = x / y
match input with
| "1" -> printfn("The result is: %d")(addition a b)
| "2" -> printfn("The result is: %d")(subtraction a b)
| "3" -> printfn("The result is: %d")(multiply a b)
| "4" -> printfn("The result is: %d")(divide a b)
ignore(Console.ReadKey())
ignore(calculator())
calculator()
以健壮的方式解析表达式,如
4+5
,通常需要依赖好的工具,如FsLex/FsYacc
或FParsec
经验丰富的开发人员喜欢从头做起(并不总是一件好事),他们可能会实现一种称为
其他人发现他们所有的解析都需要由RegEx
来回答<但是,code>RegEx在使用它所能实现的功能方面是有限的。例如,如何定义正确解析以下表达式的RegEx
:3+3*(x+3)/2
。此外,<>代码>正则表达式>代码往往是晦涩难懂的,请考虑这个常见的电子邮件验证代码:
^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$
除了复杂之外,它也是不完整的。可以在此处找到更完整的:
此外,RegEx
通常不会产生任何错误消息来告诉用户表达式解析失败的原因
许多人使用的另一种常见(不完整且低效)解析方法是使用String.Split
在运算符上拆分字符串
例如:
let r =
"1+2+3".Split '+' // Produces an array: [|"1", "2", "3"|]
|> Seq.map int // Maps to seq of ints
|> Seq.reduce (+) // Reduces the seq using (+)
根据它的逻辑结论,您可以得到一个如下所示的解析器
// Very inefficient, can't handle sub expressions, no error reporting...
// Please use this as an illustration only, not production code
let stupidParse =
let split (c: char) (s: string) = s.Split c
let trim (s: string) = s.Trim ()
let op c r f = split c >> Seq.map (trim >> f) >> Seq.reduce r
int |> op '/' (/) |> op '*' (*) |> op '-' (-) |> op '+' (+)
[<EntryPoint>]
let main argv =
let examples = [| "1"; "1-3"; "1*3"; "1 + 2*3 - 2" |]
for example in examples do
printfn "%s -> %d" example <| stupidParse example
0
//效率很低,无法处理子表达式,没有错误报告。。。
//请仅将此用作说明,而不是生产代码
让愚蠢的人来吧=
让split(c:char)(s:string)=s.split c
让修剪(s:字符串)=s.修剪()
让op c r f=split c>>Seq.map(trim>>f)>>Seq.reduce r
int |>op'/'(/)|>op'*'(*)|>op'-'(-)|>op'+'(+)
[]
让主argv=
让我们举个例子=[|“1”;“1-3”;“1*3”;“1+2*3-2”|]
举个例子吧
printfn“%s->%d”示例
我需要将一个和作为字符串传入控制台,例如“4+5”,然后解析和计算它
如果您确定字符串是由'+'
和可能的空格分隔的数字序列,则可以执行以下操作:
“4+5”.Split'+'|>Seq.sumBy(int)
它有什么作用.Split'+'
用字符+
分隔字符串,并创建字符串序列。在本例中,序列看起来像[|“4”;“5”|]
。函数Seq.sumBy
将给定函数应用于序列的每个元素,并对结果进行求和。我们使用函数(int)
将字符串转换为数字
请注意,如果字符串包含除+
以外的字符、空格和数字,或者如果没有数字的字符串由+
分隔(例如+7+8
或7++8
),则此解决方案将失败
您可能希望捕获系统.FormatException
。你最终会得到这样的结果
let sumString(输入:string):int=
尝试
input.Split'+'|>Seq.sumBy(int)
具有
| :? System.FormatException->
打印“这看起来不像一个和。让我们假设结果为零。”
0
这将只输出任何无效公式的0
。另一种避免异常的方法是丢弃所有不需要的字符和空字符串:
let sumString(输入:System.String):int=
(输入|>String.filter(有趣的c->[0';'1';'2';'3';'4';'5';'6';'7';'8';'9';'+']|>List.contains c)).Split'+'
|>顺序过滤器(((请参阅:有趣的是:公式计算器示例比您需要的更详细。我之所以发布它,是因为大多数提出类似问题的人在前进的过程中都需要添加详细信息。如果您花时间理解它,您将获得答案,并更好地理解解析和计算表达式。有趣的是:FParsec有一个简洁得体的例子: