2010-04-07 18 views
7

¿Alguno de ustedes conoce una manera fácil/limpia de encontrar una subcadena dentro de una cadena mientras ignora algunos caracteres especificados para encontrarla? Creo que un ejemplo podría explicar mejor las cosas:Buscar subcadena ignorando los caracteres especificados

  • cadena: "Hola, -this- es una cadena"
  • subcadena para encontrar: "Hola este"
  • caracteres de ignorar: "" y "-"
  • encuentra la subcadena, resultado: "Hola, -esta"

El uso de Regex no es un requisito para mí, pero agregué la etiqueta porque parece relacionada.

Actualización:

Para hacer más clara la exigencia: Necesito la subcadena que resulta con los caracteres ignorados, y no sólo una indicación de que existe la subcadena dada.

Actualización 2: Algunos de ustedes están leyendo demasiado en el ejemplo, lo siento, voy a dar otro escenario que debería funcionar:

  • cadena:?" Un & 3/3/C) 412 & "
  • subcadena de encontrar: "A41"
  • caracteres de ignorar:" &", "/", "3", "C", ")"
  • conocer la subcadena, resultado: "A & 3/3/C) 41"

Y como un bono (no se requiere per se), será genial si tampoco es seguro suponer que la subcadena para encontrar no tendrá los caracteres ignorados en ella, por ejemplo: dado el último ejemplo que deberíamos poder hacer:

  • subcadena para encontrar: "A3C412 & "
  • caracteres de ignorar:" & " "/", "3", "C", ")"
  • conocer la subcadena, resultado:" A & 3/3/C) 412 & "

Lo siento si no estaba claro antes, o aún no lo estoy :).

Actualización 3:

Gracias a todos los que ayudaron!, Esta es la aplicación que estoy trabajando por ahora:

Una aquí hay algunas pruebas:

estoy usando algunos No incluyo métodos de extensión personalizados, pero creo que deberían ser autoexplicativos (los agregaré si lo desea) He tomado muchas de sus ideas para la implementación y las pruebas, pero estoy dando la respuesta a @PierrOz porque fue uno de los primeros y me apuntó en la dirección correcta. Siéntase libre de seguir dando sugerencias como soluciones alternativas o comentarios sobre el estado actual de la impl. Si te gusta.

+0

@Fredy echar un vistazo a mi respuesta actualizada que, si he entendido correctamente, debe cubrir sus escenarios actualizados. –

+0

@Fredy: ¿es seguro concluir que espera que tanto la cadena de entrada como la cadena de búsqueda estén limpias de los caracteres no deseados antes de realizar la búsqueda? Si es así, a continuación proporcioné una solución usando RegEx y búsqueda de cadenas. –

+1

@Ahmad - Me gusta su actualización, voy a tomar algunas ideas desde allí, gracias. –

Respuesta

1

en su ejemplo, usted podría hacer:

string input = "Hello, -this-, is a string"; 
string ignore = "[-,]*"; 
Regex r = new Regex(string.Format("H{0}e{0}l{0}l{0}o{0} {0}t{0}h{0}i{0}s{0}", ignore)); 
Match m = r.Match(input); 
return m.Success ? m.Value : string.Empty; 

dinámicamente que construirían la parte [-], con todos los personajes de ignorar y se insertaría esta parte entre todos los personajes de tu consulta.

Cuida '-' en la clase []: puso al principio o al final

Así que más genéricamente, daría algo así como:

public string Test(string query, string input, char[] ignorelist) 
{ 
    string ignorePattern = "["; 
    for (int i=0; i<ignoreList.Length; i++) 
    { 
     if (ignoreList[i] == '-') 
     { 
      ignorePattern.Insert(1, "-"); 
     } 
     else 
     { 
      ignorePattern += ignoreList[i]; 
     } 
    } 

    ignorePattern += "]*"; 

    for (int i = 0; i < query.Length; i++) 
    { 
     pattern += query[0] + ignorepattern; 
    } 

    Regex r = new Regex(pattern); 
    Match m = r.Match(input); 
    return m.IsSuccess ? m.Value : string.Empty; 
} 
+0

¡Hola! Ya había pensado en esta opción y definitivamente funciona para mí. Estaba buscando algo más limpio que no me requiera construir la expresión regular de forma dinámica. pero te mereces la 'respuesta' si nada de eso aparece. Saludos. –

+0

sí No estoy seguro de que podamos evitar algo como esto. Además, en la lista de ignorados tendremos que encargarnos de personajes como "?" o "+" y todos los que se usan en la sintaxis de expresiones regulares. Todavía hay algo de trabajo en el método de prueba :) – PierrOz

+0

Tienes razón, pero está bien si eso me queda como un ejercicio :). Si vengo a implementarlo de esta manera, trataré de recordar actualizar la pregunta con la implementación más generalizada o un enlace a ella. Muchas gracias por su ayuda. –

0

Este código hace lo que quiere, aunque sugiero lo modifica para adaptarse a sus necesidades mejor:

string resultString = null; 

try 
{ 
    resultString = Regex.Match(subjectString, "Hello[, -]*this", RegexOptions.IgnoreCase).Value; 
} 
catch (ArgumentException ex) 
{ 
    // Syntax error in the regular expression 
} 
+0

Gracias, pero necesito algo más general, mi ejemplo fue eso :) –

0

usted puede hacer esto con una sola expresión regular, pero sería bastante tedioso ya que después de cada carácter que necesitaría probar cero o más caracteres ignorados. Probablemente sea más fácil quitar todos los caracteres ignorados con Regex.Replace(subject, "[-,]", ""); y luego probar si la subcadena está allí.

O la forma Regex sola

Regex.IsMatch(subject, "H[-,]*e[-,]*l[-,]*l[-,]*o[-,]* [-,]*t[-,]*h[-,]*i[-,]*s[-,]*") 
+0

Hola, creo que no puedo tira los personajes porque necesito la subcadena resultante con los caracteres. ¡Gracias! –

1

EDIT: Aquí hay una solución actualizada que aborda los puntos en su actualización reciente. La idea es la misma, excepto si tienes una subcadena que deberá insertar el patrón de ignorar entre cada personaje. Si la subcadena contiene espacios, se dividirá en los espacios e insertará el patrón de ignorar entre esas palabras. Si no necesita una funcionalidad posterior (que estaba más en línea con su pregunta original), puede eliminar la verificación Split y if que proporciona ese patrón.

Tenga en cuenta que este enfoque no va a ser el más eficiente.

string input = @"foo ?A&3/3/C)412& bar A341C2"; 
string substring = "A41"; 
string[] ignoredChars = { "&", "/", "3", "C", ")" }; 

// builds up the ignored pattern and ensures a dash char is placed at the end to avoid unintended ranges 
string ignoredPattern = String.Concat("[", 
          String.Join("", ignoredChars.Where(c => c != "-") 
                 .Select(c => Regex.Escape(c)).ToArray()), 
          (ignoredChars.Contains("-") ? "-" : ""), 
          "]*?"); 

string[] substrings = substring.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 

string pattern = ""; 
if (substrings.Length > 1) 
{ 
    pattern = String.Join(ignoredPattern, substrings); 
} 
else 
{ 
    pattern = String.Join(ignoredPattern, substring.Select(c => c.ToString()).ToArray()); 
} 

foreach (Match match in Regex.Matches(input, pattern)) 
{ 
    Console.WriteLine("Index: {0} -- Match: {1}", match.Index, match.Value); 
} 


Pruebe esta solución a cabo:

string input = "Hello, -this- is a string"; 
string[] searchStrings = { "Hello", "this" }; 
string pattern = String.Join(@"\W+", searchStrings); 

foreach (Match match in Regex.Matches(input, pattern)) 
{ 
    Console.WriteLine(match.Value); 
} 

El \W+ coincidirá con cualquier carácter no alfanumérico.Si desea especificarlos usted mismo, puede reemplazarlo con una clase de caracteres de los caracteres a ignorar, como [ ,.-]+ (siempre coloque el carácter del tablero al principio o al final para evitar especificaciones de rango no intencionadas). uso Además, si usted necesita la caja para ser ignorado RegexOptions.IgnoreCase:

Regex.Matches(input, pattern, RegexOptions.IgnoreCase) 

Si su subcadena se encuentra en la forma de una cadena completa, como "Hola este", se puede conseguir fácilmente en una forma de matriz para searchString en de esta manera:

string[] searchString = substring.Split(new[] { ' ' }, 
          StringSplitOptions.RemoveEmptyEntries); 
1

Aquí hay una opción de extensión de cadena no regex:

public static class StringExtensions 
{ 
    public static bool SubstringSearch(this string s, string value, char[] ignoreChars, out string result) 
    { 
     if (String.IsNullOrEmpty(value)) 
      throw new ArgumentException("Search value cannot be null or empty.", "value"); 

     bool found = false; 
     int matches = 0; 
     int startIndex = -1; 
     int length = 0; 

     for (int i = 0; i < s.Length && !found; i++) 
     { 
      if (startIndex == -1) 
      { 
       if (s[i] == value[0]) 
       { 
        startIndex = i; 
        ++matches; 
        ++length; 
       } 
      } 
      else 
      { 
       if (s[i] == value[matches]) 
       { 
        ++matches; 
        ++length; 
       } 
       else if (ignoreChars != null && ignoreChars.Contains(s[i])) 
       { 
        ++length; 
       } 
       else 
       { 
        startIndex = -1; 
        matches = 0; 
        length = 0; 
       } 
      } 

      found = (matches == value.Length); 
     } 

     if (found) 
     { 
      result = s.Substring(startIndex, length); 
     } 
     else 
     { 
      result = null; 
     } 
     return found; 
    } 
} 
0

Aquí está una manera no-expresión regular para hacerlo usando análisis de cadenas.

private string GetSubstring() 

    { 
     string searchString = "Hello, -this- is a string"; 
     string searchStringWithoutUnwantedChars = searchString.Replace(",", "").Replace("-", ""); 

     string desiredString = string.Empty; 
     if(searchStringWithoutUnwantedChars.Contains("Hello this")) 
      desiredString = searchString.Substring(searchString.IndexOf("Hello"), searchString.IndexOf("this") + 4); 

     return desiredString; 
    } 
0

Puede hacer algo como esto, ya que la mayoría de estas respuestas requieren la reconstrucción de la cadena de alguna forma.

cadena1 es la cadena que desea buscar a través

//Create a List(Of string) that contains the ignored characters' 
List<string> ignoredCharacters = new List<string>(); 

//Add all of the characters you wish to ignore in the method you choose 

//Use a function here to get a return 

public bool subStringExist(List<string> ignoredCharacters, string myString, string toMatch) 
{ 
    //Copy Your string to a temp 

    string tempString = myString; 
    bool match = false; 

    //Replace Everything that you don't want 

    foreach (string item in ignoredCharacters) 
    { 
     tempString = tempString.Replace(item, ""); 
    } 

    //Check if your substring exist 
    if (tempString.Contains(toMatch)) 
    { 
     match = true; 
    } 
    return match; 
} 
0

Siempre se puede utilizar una combinación de expresiones regulares y búsqueda de cadenas

public class RegExpression { 

    public static void Example(string input, string ignore, string find) 
    { 
    string output = string.Format("Input: {1}{0}Ignore: {2}{0}Find: {3}{0}{0}", Environment.NewLine, input, ignore, find); 
    if (SanitizeText(input, ignore).ToString().Contains(SanitizeText(find, ignore))) 
     Console.WriteLine(output + "was matched"); 
    else 
     Console.WriteLine(output + "was NOT matched"); 
    Console.WriteLine(); 
    } 

    public static string SanitizeText(string input, string ignore) 
    { 
    Regex reg = new Regex("[^" + ignore + "]"); 
    StringBuilder newInput = new StringBuilder(); 
    foreach (Match m in reg.Matches(input)) 
    { 
     newInput.Append(m.Value); 
    } 
    return newInput.ToString(); 
    } 

}

uso sería como

RegExpression.Example("Hello, -this- is a string", "-,", "Hello this"); //Should match 
RegExpression.Example("Hello, -this- is a string", "-,", "Hello this2"); //Should not match 
RegExpression.Example("?A&3/3/C)412&", "&/3C\\)", "A41"); // Should match 
RegExpression.Example("?A&3/3/C) 412&", "&/3C\\)", "A41"); // Should not match 
RegExpression.Example("?A&3/3/C)412&", "&/3C\\)", "A3C412&"); // Should match 

salida

de entrada: Hola, -this- es una cadena Ignorar: -, Encontrar: Hola este

se igualaron

de entrada: Hola, -this- es una cadena Ignorar: - , Encontrar: Hola esta decisión 2

fue que no coincidan

entrada:? Una & 3/3/C) 412 Ignorar: &/3C) Find: A41

se igualaron

de entrada:? A & 3/3/C) 412 & Ignorar: &/3C) Find: A41

era NO emparejado

de entrada:? A & 3/3/C) 412 & Ignorar: &/3C) Encontrar: A3C412 &

fue igualada

Cuestiones relacionadas