string - separar - Coincidencia de patrones insensibles a mayúsculas y minúsculas sobre listas de cadenas
reemplazar caracteres en python (4)
Me gusta mucho su idea de usar patrones activos F # para resolver esto. Es un poco más detallado que usar preprocesamiento, pero creo que es bastante elegante. Además, de acuerdo con algunas pautas de BCL , no debe usar ToLower
al comparar cadenas (ignorando el caso). El enfoque correcto es usar el indicador OrdinalIgnoreCase
. Aún puede definir un patrón activo agradable para hacer esto por usted:
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!"
Tiene razón en que es más detallado, pero esconde muy bien la lógica y le da suficiente poder para usar el estilo de codificación recomendado (no estoy seguro de cómo se podría hacer esto mediante el procesamiento previo).
Estoy tratando de analizar los argumentos de línea de comando en una aplicación F #. Estoy usando la coincidencia de patrones en la lista de parámetros para lograrlo. Algo como:
let rec parseCmdLnArgs =
function
| [] -> { OutputFile = None ; OtherParam = None }
| "/out" :: fileName :: rest -> let parsedRest = parseCmdLnArgs rest
{ OutputFile = Some(fileName) with parsedRest }
El problema es que quiero hacer que las mayúsculas / minúsculas sean insensibles a la vez que se preserva el caso de otras cosas. Eso significa que no puedo alterar la entrada y hacer coincidir la versión en minúscula de la entrada en su contra (esto perderá la información del caso fileName
).
He pensado en varias soluciones:
- Resort a
when
clauses que es menos que ideal. - Haga coincidir una tupla cada vez, la primera sería el parámetro real (que guardaré para su posterior procesamiento y la coincidencia con el comodín) y la segunda sería la versión en minúscula utilizada en dichas coincidencias. Esto se ve peor que el primero.
- Use patrones activos pero eso se ve demasiado detallado. Tendré que repetir cosas como
ToLower "/out"
antes de cada elemento.
¿Hay una mejor opción / patrón para hacer este tipo de cosas? Creo que este es un problema común y que debería haber una buena forma de manejarlo.
Podría hacer algo de preprocesamiento para permitir "-" o "/" al comienzo de las palabras clave, y para normalizar el caso:
let normalize (arg:string) =
if arg.[0] = ''/'' || arg.[0] = ''-'' then
("-" + arg.[1..].ToLower())
else arg
let normalized = args |> List.map normalize
Tal vez no sea lo ideal, pero no es como si cualquier usuario tuviera la paciencia suficiente para escribir tantos parámetros de línea de comandos que recorrerlos dos veces es notablemente lento.
Puede usar guardias para que coincida con su oferta:
let rec parseCmdLnArgs =
function
| [] -> { OutputFile = None ; OtherParam = None }
| root :: fileName :: rest when root.ToUpper() = "/OUT" -> let parsedRest = parseCmdLnArgs rest
{ OutputFile = Some(fileName) with parsedRest }
Se topó con esto en busca de una solución a un problema similar, y aunque la solución de Tomas funciona para cadenas individuales, no ayuda con el problema original de la coincidencia de patrones con las listas de cadenas. Una versión modificada de su patrón activo permite listas de correspondencia:
let (|InvariantEqual|_|) : string list -> string list -> unit option =
fun x y ->
let f : unit option -> string * string -> unit option =
fun state (x, y) ->
match state with
| None -> None
| Some() ->
if x.Equals(y, System.StringComparison.OrdinalIgnoreCase)
then Some()
else None
if x.Length <> y.Length then None
else List.zip x y |> List.fold f (Some())
match ["HeLlO wOrLd"] with
| InvariantEqual ["hello World";"Part Two!"] -> printfn "Bad input"
| InvariantEqual ["hello WORLD"] -> printfn "World says hello"
| _ -> printfn "No match found"
No he podido averiguar cómo hacer que coincida con los marcadores de posición correctamente para hacer | InvariantEqual "/out" :: fileName :: rest -> ...
| InvariantEqual "/out" :: fileName :: rest -> ...
aún, pero si conoce el contenido completo de la lista, es una mejora.