sensitive - content string c#
"No contiene mayúsculas y minúsculas" Contiene(cadena) (24)
Solo .NET Core 2.0+ (a partir de ahora)
.NET Core ha tenido un par de métodos para lidiar con esto desde la versión 2.0:
- String.Contains (Char, StringComparison )
- String.Contains (String, StringComparison )
Ejemplo:
"Test".Contains("test", System.StringComparison.CurrentCultureIgnoreCase);
Con el tiempo, probablemente ingresarán al estándar .NET y, a partir de ahí, a todas las otras implementaciones de la Biblioteca de clases base.
¿Hay alguna manera de hacer que el siguiente retorno sea verdadero?
string title = "ASTRINGTOTEST";
title.Contains("string");
Parece que no hay una sobrecarga que me permita configurar la sensibilidad del caso. Actualmente, ME MAYOR MEJORO a ambos, pero eso es una tontería (por lo que me refiero a los problemas de i18n que vienen con la cubierta hacia arriba y hacia abajo).
ACTUALIZAR
Esta pregunta es antigua y desde entonces me he dado cuenta de que pedí una respuesta simple para un tema realmente vasto y difícil si te interesa investigarlo por completo.
Para la mayoría de los casos, en el lenguaje monolingual, el código en inglés basará this respuesta. Sospecho que la mayoría de las personas que vienen aquí están en esta categoría, esta es la respuesta más popular.
This embargo, This respuesta plantea el problema inherente de que no podemos comparar el texto sin distinción de mayúsculas y minúsculas hasta que sepamos que ambos textos son de la misma cultura y sabemos qué es esa cultura. Esta es quizás una respuesta menos popular, pero creo que es más correcta y es por eso que la marqué como tal.
Al igual que esto:
string s="AbcdEf";
if(s.ToLower().Contains("def"))
{
Console.WriteLine("yes");
}
El método InStr
del ensamblaje VisualBasic es el mejor si tiene alguna inquietud acerca de la internacionalización (o podría volver a implementarla). Al mirar en él, dotNeetPeek muestra que no solo tiene mayúsculas y minúsculas, sino también caracteres de tipo kana y de ancho completo vs. medio ancho (en su mayoría relevantes para idiomas asiáticos, aunque también existen versiones de ancho completo del alfabeto romano ). Me estoy saltando algunos detalles, pero echa un vistazo al método privado InternalInStrText
:
private static int InternalInStrText(int lStartPos, string sSrc, string sFind)
{
int num = sSrc == null ? 0 : sSrc.Length;
if (lStartPos > num || num == 0)
return -1;
if (sFind == null || sFind.Length == 0)
return lStartPos;
else
return Utils.GetCultureInfo().CompareInfo.IndexOf(sSrc, sFind, lStartPos, CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth);
}
El truco aquí es buscar la cadena, ignorando el caso, pero mantenerlo exactamente igual (con el mismo caso).
var s="Factory Reset";
var txt="reset";
int first = s.IndexOf(txt, StringComparison.InvariantCultureIgnoreCase) + txt.Length;
var subString = s.Substring(first - txt.Length, txt.Length);
La salida es "Reset"
En última instancia, una operación genérica "contiene" se reduce a una función como esta,
/// <summary>
/// Determines whether the source contains the sequence.
/// </summary>
/// <typeparam name="T">The type of the items in the sequences.</typeparam>
/// <param name="sourceEnumerator">The source enumerator.</param>
/// <param name="sequenceEnumerator">The sequence enumerator.</param>
/// <param name="equalityComparer">An equality comparer.</param>
/// <remarks>
/// An empty sequence will return <c>true</c>.
/// The sequence must support <see cref="IEnumerator.Reset"/>
/// if it does not begin the source.
/// </remarks>
/// <returns>
/// <c>true</c> if the source contains the sequence;
/// otherwise <c>false</c>.
/// </returns>
public static bool Contains<T>(
IEnumerator<T> sourceEnumerator,
IEnumerator<T> sequenceEnumerator,
IEqualityComparer<T> equalityComparer)
{
if (equalityComparer == null)
{
equalityComparer = EqualityComparer<T>.Default;
}
while (sequenceEnumerator.MoveNext())
{
if (sourceEnumerator.MoveNext())
{
if (!equalityComparer.Equals(
sourceEnumerator.Current,
sequenceEnumerator.Current))
{
sequenceEnumerator.Reset();
}
}
else
{
return false;
}
}
return true;
}
esto se puede envolver de forma trivial en una versión de extensión que acepte IEnumerable
como este,
public static bool Contains<T>(
this IEnumerable<T> source,
IEnumerable<T> sequence,
IEqualityComparer<T> equalityComparer = null)
{
if (sequence == null)
{
throw new ArgumentNullException("sequence");
}
using(var sequenceEnumerator = sequence.GetEnumerator())
using(var sourceEnumerator = source.GetEnumerator())
{
return Contains(
sourceEnumerator,
sequenceEnumerator,
equalityComparer);
}
}
Ahora, esto funcionará para la comparación ordinal de cualquier secuencia, incluidas las cadenas, ya que la string
implementa IEnumerable<char>
,
// The optional parameter ensures the generic overload is invoked
// not the string.Contains() implementation.
"testable".Contains("est", EqualityComparer<char>.Default)
Sin embargo, como sabemos, las cadenas no son genéricas, son especializadas. Hay dos factores clave en juego.
- El problema de la "carcasa" que a su vez tiene varios casos de borde dependientes del idioma
- La cuestión más bien complicada de cómo un conjunto de "Elementos de texto" (letras / números / símbolos, etc.) se representan mediante puntos de código Unicode y qué secuencias válidas de caracteres pueden representar una cadena dada, los detalles se amplían en these answers .
El efecto neto es el mismo. Las cadenas que puede afirmar que son lingüísticamente iguales pueden representarse válidamente mediante diferentes combinaciones de caracteres. Además, las reglas de validez cambian entre culturas.
Todo esto lleva a una implementación especializada de "Contiene" basada en cadenas como esta.
using System.Globalization;
public static bool Contains(
this string source,
string value,
CultureInfo culture = null,
CompareOptions options = CompareOptions.None)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
var compareInfo = culture == null ?
CultureInfo.CurrentCulture.CompareInfo :
culture.CompareInfo;
var sourceEnumerator = StringInfo.GetTextElementEnumerator(source);
var sequenceEnumerator = StringInfo.GetTextElementEnumerator(value);
while (sequenceEnumerator.MoveNext())
{
if (sourceEnumerator.MoveNext())
{
if (!(compareInfo.Compare(
sourceEnumerator.Current,
sequenceEnumerator.Current,
options) == 0))
{
sequenceEnumerator.Reset();
}
}
else
{
return false;
}
}
return true;
}
Esta función se puede utilizar para realizar una "distinción de mayúsculas y minúsculas" específica para cada caso que funcionará, independientemente de la normalización de las cadenas. p.ej
"testable".Contains("EST", StringComparer.CurrentCultureIgnoreCase)
Estas son las soluciones más fáciles.
Por índice de
string title = "STRING"; if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1) { // contains }
Cambiando caso
string title = "STRING"; bool contains = title.ToLower().Contains("string")
Por Regex
Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
Esto es bastante similar a otro ejemplo aquí, pero he decidido simplificar la enumeración a bool, principalmente porque normalmente no se necesitan otras alternativas. Aquí está mi ejemplo:
public static class StringExtensions
{
public static bool Contains(this string source, string toCheck, bool bCaseInsensitive )
{
return source.IndexOf(toCheck, bCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0;
}
}
Y el uso es algo como:
if( "main String substring".Contains("SUBSTRING", true) )
....
Esto es limpio y simple.
Regex.IsMatch(file, fileNamestr, RegexOptions.IgnoreCase)
La clase StringExtension es el camino a seguir, he combinado un par de las publicaciones anteriores para dar un ejemplo de código completo:
public static class StringExtensions
{
/// <summary>
/// Allows case insensitive checks
/// </summary>
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
return source.IndexOf(toCheck, comp) >= 0;
}
}
Para probar si el paragraph
cadena contiene la word
cadena (gracias @QuarterMeister)
culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0
Donde culture
es la instancia de CultureInfo
describe el idioma en el que está escrito el texto.
Esta solución es transparente sobre la definición de insensibilidad a los casos, que depende del lenguaje . Por ejemplo, el idioma inglés utiliza los caracteres I
y i
para las versiones en mayúsculas y minúsculas de la novena letra, mientras que el idioma turco usa estos caracteres para las letras undécima y duodécima de su alfabeto de 29 letras. La versión turca en mayúsculas de ''i'' es el carácter desconocido ''İ''.
Así, las cadenas tin
y TIN
son la misma palabra en inglés , pero diferentes palabras en turco . Según tengo entendido, uno significa "espíritu" y el otro es una palabra onomatopeya. (Turcos, corríjanme si me equivoco o sugiera un ejemplo mejor)
Para resumir, solo puede responder a la pregunta "estas dos cadenas son iguales pero en casos diferentes" si sabe en qué idioma se encuentra el texto . Si no lo sabes, tendrás que hacer una patada de despeje. Dada la hegemonía del software en inglés, probablemente deberías recurrir a CultureInfo.InvariantCulture
, porque estará equivocado en formas familiares.
Podría usar el método String.IndexOf y pasar StringComparison.OrdinalIgnoreCase
como el tipo de búsqueda que se usará:
string title = "STRING";
bool contains = title.IndexOf("string", StringComparison.OrdinalIgnoreCase) >= 0;
Aún mejor es definir un nuevo método de extensión para la cadena:
public static class StringExtensions
{
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
return source?.IndexOf(toCheck, comp) >= 0;
}
}
Tenga en cuenta, que la propagación nula ?.
está disponible desde C # 6.0 (VS 2015), para uso en versiones anteriores
if (source == null) return false;
return source.IndexOf(toCheck, comp) >= 0;
USO:
string title = "STRING";
bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
Puedes usar IndexOf()
esta manera:
string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
{
// The string exists in the original
}
Como 0 (cero) puede ser un índice, verifique contra -1.
La posición del índice basada en cero del valor si se encuentra esa cadena, o -1 si no lo es. Si el valor es String.Empty, el valor de retorno es 0.
Puedes usar la función string.indexof ()
. Esto será insensible a las mayúsculas.
Sé que este no es el C #, pero en el marco (VB.NET) ya existe tal función
Dim str As String = "UPPERlower"
Dim b As Boolean = InStr(str, "UpperLower")
Variante C #:
string myString = "Hello World";
bool contains = Microsoft.VisualBasic.Strings.InStr(myString, "world");
Si desea verificar si su cadena pasada está en cadena, entonces hay un método simple para eso.
string yourStringForCheck= "abc";
string stringInWhichWeCheck= "Test abc abc";
bool isContaines = stringInWhichWeCheck.ToLower().IndexOf(yourStringForCheck.ToLower()) > -1;
This boolean value will return if string contains or not
Siempre puedes subir o bajar las cuerdas primero.
string title = "string":
title.ToUpper().Contains("STRING") // returns true
Vaya, acabo de ver ese último bit. Una comparación que no distingue entre mayúsculas y minúsculas *
probablemente *
haría lo mismo de todos modos, y si el rendimiento no es un problema, no veo un problema con la creación de copias en mayúsculas y la comparación. Podría haber jurado que una vez vi una comparación entre mayúsculas y minúsculas una vez ...
Solución alternativa utilizando Regex:
bool contains = Regex.IsMatch("StRiNG to search", "string", RegexOptions.IgnoreCase);
darse cuenta
Como @cHao ha señalado en su comentario, hay situaciones que harán que esta solución arroje resultados incorrectos. Asegúrese de saber lo que está haciendo antes de implementar esta solución al azar.
Un problema con la respuesta es que lanzará una excepción si una cadena es nula. Puedes agregar eso como un cheque para que no:
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
if (string.IsNullOrEmpty(toCheck) || string.IsNullOrEmpty(source))
return true;
return source.IndexOf(toCheck, comp) >= 0;
}
Usar un RegEx es una forma directa de hacer esto:
Regex.IsMatch(title, "string", RegexOptions.IgnoreCase);
Utilizar esta:
string.Compare("string", "STRING", new System.Globalization.CultureInfo("en-US"), System.Globalization.CompareOptions.IgnoreCase);
Manera simple para novato:
title.ToLower().Contains("string");//of course "string" is lowercase.
OrdinalIgnoreCase, CurrentCultureIgnoreCase o InvariantCultureIgnoreCase?
Como esto falta, aquí hay algunas recomendaciones sobre cuándo usar cuál:
Dos
- Use
StringComparison.OrdinalIgnoreCase
para las comparaciones como su valor predeterminado seguro para la coincidencia de cadenas cultural-agnostic. - Utilice
StringComparison.OrdinalIgnoreCase
comparaciones deStringComparison.OrdinalIgnoreCase
para aumentar la velocidad. - Utilice las operaciones de cadena
StringComparison.CurrentCulture-based
cuando muestre la salida al usuario. - Cambie el uso actual de las operaciones de cadena basadas en la cultura invariable para usar el
StringComparison.Ordinal
oStringComparison.OrdinalIgnoreCase
no lingüístico cuando la comparación es
lingüísticamente irrelevante (simbólico, por ejemplo). - Use
ToUpperInvariant
lugar deToLowerInvariant
cuando normalice cadenas para la comparación.
No hacer
- Utilice sobrecargas para operaciones de cadena que no especifican explícita o implícitamente el mecanismo de comparación de cadena.
- Utilice
StringComparison.InvariantCulture
string basado en
operaciones en la mayoría de los casos; una de las pocas excepciones seria
Persistiendo datos lingüísticamente significativos pero culturalmente agnósticos.
Basado en estas reglas debes usar:
string title = "STRING";
if (title.IndexOf("string", 0, StringComparison.[YourDecision]) != -1)
{
// The string exists in the original
}
mientras que [YourDecision] depende de las recomendaciones de arriba.
enlace de la fuente: http://msdn.microsoft.com/en-us/library/ms973919.aspx
if ("strcmpstring1".IndexOf(Convert.ToString("strcmpstring2"), StringComparison.CurrentCultureIgnoreCase) >= 0){return true;}else{return false;}
public static class StringExtension
{
#region Public Methods
public static bool ExContains(this string fullText, string value)
{
return ExIndexOf(fullText, value) > -1;
}
public static bool ExEquals(this string text, string textToCompare)
{
return text.Equals(textToCompare, StringComparison.OrdinalIgnoreCase);
}
public static bool ExHasAllEquals(this string text, params string[] textArgs)
{
for (int index = 0; index < textArgs.Length; index++)
if (ExEquals(text, textArgs[index]) == false) return false;
return true;
}
public static bool ExHasEquals(this string text, params string[] textArgs)
{
for (int index = 0; index < textArgs.Length; index++)
if (ExEquals(text, textArgs[index])) return true;
return false;
}
public static bool ExHasNoEquals(this string text, params string[] textArgs)
{
return ExHasEquals(text, textArgs) == false;
}
public static bool ExHasNotAllEquals(this string text, params string[] textArgs)
{
for (int index = 0; index < textArgs.Length; index++)
if (ExEquals(text, textArgs[index])) return false;
return true;
}
/// <summary>
/// Reports the zero-based index of the first occurrence of the specified string
/// in the current System.String object using StringComparison.InvariantCultureIgnoreCase.
/// A parameter specifies the type of search to use for the specified string.
/// </summary>
/// <param name="fullText">
/// The string to search inside.
/// </param>
/// <param name="value">
/// The string to seek.
/// </param>
/// <returns>
/// The index position of the value parameter if that string is found, or -1 if it
/// is not. If value is System.String.Empty, the return value is 0.
/// </returns>
/// <exception cref="ArgumentNullException">
/// fullText or value is null.
/// </exception>
public static int ExIndexOf(this string fullText, string value)
{
return fullText.IndexOf(value, StringComparison.OrdinalIgnoreCase);
}
public static bool ExNotEquals(this string text, string textToCompare)
{
return ExEquals(text, textToCompare) == false;
}
#endregion Public Methods
}