strings stringcomparison comparestring comparar cadenas alfabeticamente c# switch-statement

stringcomparison - string equals c#



Cómo hacer que la declaración del conmutador C#use IgnoreCase (7)

Como parece saber, la minúscula de dos cadenas y su comparación no es lo mismo que hacer una comparación de caso ignorado. Hay muchas razones para esto. Por ejemplo, el estándar Unicode permite que el texto con signos diacríticos se codifique de múltiples maneras. Algunos caracteres incluyen tanto el carácter base como el signo diacrítico en un único punto de código. Estos caracteres también pueden representarse como el carácter base seguido de un carácter diacrítico de combinación. Estas dos representaciones son iguales para todos los propósitos, y las comparaciones de cadenas con reconocimiento de cultura en .NET Framework las identificará correctamente como iguales, ya sea con CurrentCulture o InvariantCulture (con o sin IgnoreCase). Una comparación ordinal, por otro lado, los considerará incorrectamente como desiguales.

Desafortunadamente, el switch no hace nada más que una comparación ordinal. Una comparación ordinal es adecuada para ciertos tipos de aplicaciones, como el análisis de un archivo ASCII con códigos rígidamente definidos, pero la comparación de cadenas ordinales es incorrecta para la mayoría de los demás usos.

Lo que hice en el pasado para obtener el comportamiento correcto es simular mi propia declaración de cambio. Hay muchas formas de hacer esto. Una forma sería crear una List<T> de pares de cadenas de casos y delegados. La lista se puede buscar utilizando la comparación de cadenas adecuada. Cuando se encuentra la coincidencia, se puede invocar al delegado asociado.

Otra opción es hacer la cadena obvia de declaraciones if . Esto generalmente no es tan malo como parece, ya que la estructura es muy regular.

Lo bueno de esto es que no hay realmente ninguna penalización en el rendimiento al burlarse de su propia funcionalidad de conmutación cuando compara contra cadenas. El sistema no creará una tabla de salto O (1) de la manera que sea posible con números enteros, por lo que de todos modos se compararán cada cadena de a una.

Si hay muchos casos que comparar, y el rendimiento es un problema, la opción de la List<T> descrita anteriormente podría reemplazarse con un diccionario ordenado o una tabla hash. Entonces, el rendimiento puede coincidir o superar la opción de declaración de cambio.

Aquí hay un ejemplo de la lista de delegados:

delegate void CustomSwitchDestination(); List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList; CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound); void CustomSwitch(string value) { foreach (var switchOption in customSwitchList) if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase)) { switchOption.Value.Invoke(); return; } defaultSwitchDestination.Invoke(); }

Por supuesto, es probable que desee agregar algunos parámetros estándar y posiblemente un tipo de devolución al delegado CustomSwitchDestination. ¡Y querrás hacer mejores nombres!

Si el comportamiento de cada uno de sus casos no es susceptible de delegar la invocación de esta manera, por ejemplo, si son necesarios diferentes parámetros, entonces quedará atrapado con sentencias encadenadas. También he hecho esto algunas veces.

if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase)) { s = "window"; } else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase)) { s = "really big window"; } else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase)) { s = "broken window"; }

Si tengo una declaración de mayúsculas y minúsculas en la que el objeto en el interruptor es una cadena, ¿es posible hacer de todos modos ignorar la comparación de caso?

Tengo por ejemplo:

string s = "house"; switch (s) { case "houSe": s = "window"; }

Obtendrá una "ventana" de valor. ¿Cómo anular la declaración de mayúsculas y minúsculas para que compare las cadenas usando ignoreCase?


En algunos casos, puede ser una buena idea usar una enumeración. Por lo tanto, primero analizaremos la enumeración (con ignorar indicador de casilla verdadero) y haremos un cambio en la enumeración.

SampleEnum Result; bool Success = SampleEnum.TryParse(inputText, true, out Result); if(!Success){ //value was not in the enum values }else{ switch (Result) { case SampleEnum.Value1: break; case SampleEnum.Value2: break; default: //do default behaviour break; } }


Espero que esto ayude a tratar de convertir toda la cadena en un caso particular, ya sea en minúsculas o Mayúsculas y usar la cadena en minúsculas para comparar:

public string ConvertMeasurements(string unitType, string value) { switch (unitType.ToLower()) { case "mmol/l": return (Double.Parse(value) * 0.0555).ToString(); case "mg/dl": return (double.Parse(value) * 18.0182).ToString(); } }


Lo siento por esta nueva publicación de una pregunta anterior, pero hay una nueva opción para resolver este problema usando C # 7 (VS 2017).

C # 7 ahora ofrece "coincidencia de patrones", y se puede usar para abordar este problema de la siguiente manera:

string houseName = "house"; // value to be tested, ignoring case string windowName; // switch block will set value here switch (true) { case bool b when houseName.Equals("MyHouse", StringComparison.InvariantCultureIgnoreCase): windowName = "MyWindow"; break; case bool b when houseName.Equals("YourHouse", StringComparison.InvariantCultureIgnoreCase): windowName = "YourWindow"; break; case bool b when houseName.Equals("House", StringComparison.InvariantCultureIgnoreCase): windowName = "Window"; break; default: windowName = null; break; }

Esta solución también aborda el problema mencionado en la respuesta de @Jeffrey L. Whitledge de que la comparación de cadenas que no distingue entre mayúsculas y minúsculas no es lo mismo que la comparación de dos cadenas de cassettes inferiores.

Por cierto, hubo un artículo interesante en febrero de 2017 en Visual Studio Magazine que describe la coincidencia de patrones y cómo puede usarse en bloques de casos. Por favor, eche un vistazo: coincidencia de patrones en C # 7.0 Case Blocks

EDITAR

A la luz de la respuesta de @ LewisM, es importante señalar que la declaración de switch tiene un comportamiento nuevo e interesante. Es decir, si la declaración de su case contiene una declaración de variable, entonces el valor especificado en la parte del switch se copia en la variable declarada en el case . En el siguiente ejemplo, el valor true se copia en la variable local b . Además de eso, la variable b no se utiliza, y existe solo para que exista la cláusula when en el enunciado case :

switch(true) { case bool b when houseName.Equals("X", StringComparison.InvariantCultureIgnoreCase): windowName = "X-Window";): break; }

Como señala @LewisM, esto se puede utilizar para beneficiarse, ya que el beneficio es que lo que se compara se encuentra realmente en la sentencia switch , como ocurre con el uso clásico de la declaración switch . Además, los valores temporales declarados en la declaración de case pueden evitar cambios no deseados o inadvertidos en el valor original:

switch(houseName) { case string hn when hn.Equals("X", StringComparison.InvariantCultureIgnoreCase): windowName = "X-Window"; break; }


Un enfoque más simple es simplemente la minúscula de su cadena antes de entrar en la declaración de cambio, y tener los casos más bajos.

En realidad, la parte superior es un poco mejor desde el punto de vista del rendimiento de un extremo de nanosegundos, pero es menos natural de observar.

P.ej:

string s = "house"; switch (s.ToLower()) { case "house": s = "window"; break; }


Una extensión a la respuesta por @STLDeveloperA. Una nueva forma de hacer una evaluación de enunciados sin múltiples sentencias if a partir de c # 7 es usar el patrón que coincide con la instrucción Switch, similar a la forma en que @STLDeveloper, aunque de esta manera está activando la variable que se está conmutando.

string houseName = "house"; // value to be tested string s; switch (houseName) { case var name when name.Equals("Bungalow", StringComparison.InvariantCultureIgnoreCase): s = "Single glazed"; break; case var name when name.Equals("Church", StringComparison.InvariantCultureIgnoreCase); s = "Stained glass"; break; ... default: s = "No windows (cold or dark)" break; }

La revista visual studio tiene un buen artículo sobre patrones de bloques de cajas que pueden valer la pena mirar.


Una posible forma sería utilizar un diccionario de casos ignorados con un delegado de acción.

string s = null; var dic = new Dictionary<string, Action>(StringComparer.CurrentCultureIgnoreCase) { {"house", () => s = "window"}, {"house2", () => s = "window2"} }; dic["HouSe"]();