Нечувствительное к регистру сопоставление с образцом по спискам строк

Я пытаюсь проанализировать параметры командной строки в приложении 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" перед каждым объектом.

Существует ли более оптимальный вариант / шаблон для того, чтобы сделать подобные материал? Я думаю, что это - типичная проблема и должен быть хороший способ обработать ее.

17
задан Mehrdad Afshari 23 September 2010 в 00:24
поделиться

3 ответа

Мне очень нравится ваше представление о использование активных шаблонов F # для решения этой проблемы. Это немного более подробно, чем при использовании предварительной обработки, но я думаю, что это довольно элегантно. Кроме того, согласно некоторым рекомендациям BCL , вы не должны использовать ToLower при сравнении строк (игнорируя регистр). Правильный подход - использовать флаг OrdinalIgnoreCase . Вы все еще можете определить хороший активный шаблон, чтобы сделать это за вас:

open System

let (|InvariantEqual|_|) (str:string) arg = 
  if String.Compare(str, arg, StringComparison.OrdinalIgnoreCase) = 0
    then Some() else None

match "HellO" with
| InvariantEqual "hello" -> printfn "yep!"
| _ -> printfn "Nop!"    

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

30
ответ дан 30 November 2019 в 12:00
поделиться

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

let normalize (arg:string) =
    if arg.[0] = '/' || arg.[0] = '-' then 
        ("-" + arg.[1..].ToLower())
    else arg
let normalized = args |> List.map normalize

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

2
ответ дан 30 November 2019 в 12:00
поделиться

Вы можете использовать средства защиты в соответствии с вашей сделкой:

let rec parseCmdLnArgs = 
  function
  | [] -> { OutputFile = None ; OtherParam = None }
  | root :: fileName :: rest when root.ToUpper() = "/OUT" -> let parsedRest = parseCmdLnArgs rest
                                  { OutputFile = Some(fileName) with parsedRest }
2
ответ дан 30 November 2019 в 12:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: