字符串列表上不区分大小写的模式匹配
我正在尝试解析 F# 应用程序中的命令行参数。我使用参数列表的模式匹配来完成它。比如:
let rec parseCmdLnArgs =
function
| [] -> { OutputFile = None ; OtherParam = None }
| "/out" :: fileName :: rest -> let parsedRest = parseCmdLnArgs rest
{ OutputFile = Some(fileName) with parsedRest }
问题是我想让 "/out"
匹配不区分大小写,同时保留其他内容的大小写。这意味着我无法更改输入并将输入的小写版本与其进行匹配(这将丢失 fileName
大小写信息)。
我考虑过几种解决方案:
- 求助于
when
子句,这不太理想。 - 每次匹配一个元组,第一个是实际参数(我将保存它以供进一步处理,并将通配符匹配它),第二个是此类匹配中使用的小写版本。这看起来比第一个更糟糕。
- 使用主动模式,但这看起来太冗长了。我必须在每个项目之前重复诸如
ToLower "/out"
之类的内容。
做这些事情有更好的选择/模式吗?我认为这是一个普遍的问题,应该有一个好的方法来处理它。
I'm trying to parse command line arguments in an F# application. I'm using pattern matching over parameters list to accomplish it. Something like:
let rec parseCmdLnArgs =
function
| [] -> { OutputFile = None ; OtherParam = None }
| "/out" :: fileName :: rest -> let parsedRest = parseCmdLnArgs rest
{ OutputFile = Some(fileName) with parsedRest }
The problem is I want to make "/out"
match case insensitive while preserving the case of other stuff. That means I can't alter the input and match the lowercase version of the input against it (this will lose the fileName
case information).
I have thought about several solutions:
- Resort to
when
clauses which is less than ideal. - Match a tuple each time, the first would be the actual parameter (which I'll just save for further processing and will wildcard match it) and the second would be the lowercased version used in such matchings. This looks worse than the first.
- Use active patterns but that looks too verbose. I'll have to repeat things like
ToLower "/out"
before every item.
Is there a better option/pattern for doing these kind of stuff? I think this is a common problem and there should be a good way to handle it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我非常喜欢您使用 F# 主动模式来解决这个问题的想法。它比使用预处理要冗长一些,但我认为它非常优雅。另外,根据一些 BCL 指南,您不应该比较字符串时不要使用ToLower(忽略大小写)。正确的方法是使用 OrdinalIgnoreCase 标志。您仍然可以定义一个很好的活动模式来为您执行此操作:
您是对的,它更冗长,但它很好地隐藏了逻辑,并且它为您提供了足够的权力来使用推荐的编码风格(我不确定这如何能够使用预处理来完成)。
I quite like your idea of using F# active patterns to solve this. It is a bit more verbose than using pre-processing, but I think it's quite elegant. Also, according to some BCL guidelines, you shouldn't be using
ToLower
when comparing strings (ignoring the case). The right approach is to useOrdinalIgnoreCase
flag. You can still define a nice active pattern to do this for you:You're right that it's more verbose, but it nicely hides the logic and it gives you enough power to use the recommended coding style (I'm not sure how this could be done using pre-processing).
我可能会做一些预处理,以允许在关键字开头使用“-”或“/”,并规范化情况:
这可能并不理想,但并不是任何用户都会有足够的耐心来输入许多命令行参数循环遍历它们两次明显很慢。
I might do some pre-processing to allow for either "-" or "/" at the beginning of keywords, and to normalize the case:
It's perhaps not ideal, but it's not like any user is going to have enough patience to type so many command-line parameters that looping through them twice is noticeably slow.
您可以使用守卫来匹配您的交易:
You can use guards to match your deal:
遇到这个问题是为了寻找类似问题的解决方案,虽然托马斯的解决方案适用于单个字符串,但它对解决字符串列表的模式匹配的原始问题没有帮助。他的活动模式的修改版本允许匹配列表:
我一直无法弄清楚如何使其与占位符正确匹配以执行
| InvariantEqual "/out" :: 文件名 :: 休息 -> ...
还没有,但如果您知道列表的全部内容,那就是一个进步。Ran into this looking for a solution to a similar issue, and while Tomas' solution works for individual strings, it doesn't help with the original issue of pattern matching against lists of strings. A modified version of his active pattern allows matching lists:
I haven't been able to figure out how to make it match with placeholders properly to do
| InvariantEqual "/out" :: fileName :: rest -> ...
yet, but if you know the entire contents of the list, it's an improvement.