2010-06-29 15 views
5

Tengo el siguiente método que he creado que funciona bien si realmente está el delimitador en cuestión. Quiero mantener esto fuera de LINQ por ahora ...Método de utilidad de división de cadenas Problema cuando no se incluyen delimitadores

p.

Si paso la cadena "123; 322; 323", funciona muy bien.

Pero si solo paso en un valor de cadena sin el delimitador como "123" obviamente no se dividirá ya que no hay delimitador. Estoy tratando de averiguar la mejor manera de comprobar y dar cuenta de esto y ser capaz de escupir que un valor de nuevo en la lista

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new List<int>(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    string[] values = stringToSplit.Split(splitDelimiter); 

    if (values.Length < 1) 
     return list; 

    foreach (string s in values) 
    { 
     int i; 
     if (Int32.TryParse(s, out i)) 
      list.Add(i); 
    } 

    return list; 
} 

Actualizado: Esto es lo que ocurrió con la que parece funcionar, pero seguro es largo

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
    { 
     List<int> list = new IntList(); 

     if (string.IsNullOrEmpty(stringToSplit)) 
      return list; 

     if (stringToSplit.Contains(splitDelimiter.ToString())) 
     { 
      string[] values = stringToSplit.Split(splitDelimiter); 

      if (values.Length <= 1) 
       return list; 

      foreach (string s in values) 
      { 
       int i; 
       if (Int32.TryParse(s, out i)) 
        list.Add(i); 
      } 
     } 
     else if (stringToSplit.Length > 0) 
     { 
      int i; 
      if(Int32.TryParse(stringToSplit, out i)) 
       list.Add(i); 
     } 

     return list; 
    } 
+0

¿Has probado esto? – Marc

+0

¿O lo depuró? – tster

+0

Sí, no publiqué a menos que lo haya depurado. – PositiveGuy

Respuesta

2

Hay MUCHAS revisiones innecesarias para condiciones que no importan a la lógica central del método.

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new IntList(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    //this if is not necessary. As others have said, Split will return a string[1] with the original string if no delimiter is found 
    if (stringToSplit.Contains(splitDelimiter.ToString())) 
    { 
     string[] values = stringToSplit.Split(splitDelimiter); 

     //why check this? if there are no values, the foreach will do nothing and fall through to a return anyway. 
     if (values.Length <= 1) 
      return list; 

     foreach (string s in values) 
     { 
      int i; 
      if (Int32.TryParse(s, out i)) 
       list.Add(i); 
     } 
    } 
    //again, this is rendered redundant due to previous comments 
    else if (stringToSplit.Length > 0) 
    { 
     int i; 
     if(Int32.TryParse(stringToSplit, out i)) 
      list.Add(i); 
    } 

    return list; 
} 

Pruebe esto. Usted con suerte tiene algunas pruebas de unidad llamando a este método para asegurarse de que funciona ... ¿verdad?

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new IntList(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    foreach(var s in stringToSplit.Split(splitDelimiter)) 
    { 
     int i; 
     if(int.TryParse(s, out i)) 
      list.Add(i); 
    } 
    return list; 
} 
+0

Muchas gracias. Esta es una buena respuesta y sí, estoy tratando de reducir mi código innecesario en general ...este fue un gran hilo para darse cuenta de cuánto desorden tenía allí. Yo no lo vi al principio. – PositiveGuy

+0

Gracias por recordarme acerca de las pruebas unitarias. El problema es que trabajo en un código y ejecuto una tienda donde la calidad no está en primer plano, por lo tanto no encuentro tiempo. Si tengo a mi jefe respirando en mi cuello, diciendo que "no tiene que ser perfecto" o "eso está por la borda" cuando simplemente intento crear un código simple de limpieza reutilizable, eso no deja espacio para las pruebas unitarias. "Encuentra el tiempo entonces" ... otra vez, el jefe sigue controlando, quiere que lo empujen, esto no está bajo mi control. El mismo viejo problema, el desarrollo son tiendas de sudor en muchos casos, caos, basura. Es una de las razones por las que odio mi trabajo a veces. – PositiveGuy

+0

@coffeeaddict, la prueba unitaria hará que se desarrolle más rápido, por lo que no podrá "encontrar el tiempo" para escribir pruebas, no es excusa, ya que ofrecerá una funcionalidad más lenta sin pruebas unitarias. – tster

4

Cambiar esta condición:

if (values.Length <= 1) 
    return list; 

Para:

if (values.Length <= 0) 
    return list; 

Esto funciona porque String.Split devuelve la cadena original si no puede encontrar el delimitador:

// stringToSplit does not contain the splitDelimiter 
string[] values = stringToSplit.Split(splitDelimiter); 
// values is a string array containing one value - stringToSplit 
+0

O alternativamente, 'if (! Values.Any())', pero +1 para encontrar el error y la explicación de lo que '.Split' está haciendo por él. – Marc

+0

si Split devuelve la cadena original si no se puede encontrar el delimitador, entonces values.Length debe ser 1 ¿verdad? (y el ítem está en los valores [0]) La comprobación de <= 1 es entonces correcta. – RvdK

+0

@PowerRoy - Está intentando verificar si la matriz está vacía y luego devolver una lista vacía (lea todo el código). La matriz está vacía cuando no hay elementos en ella ('values.Length <= 0'). – Oded

0

Una aplicación más corto que podría considerar.

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    int i; 
    return stringToSplit.Split(splitDelimiter) 
     .Where(str => int.TryParse(str, out i)) 
     .Select(str => int.Parse(str)) 
     .ToList(); 
} 
+1

¿Acaso 'i' no termina siendo la última cadena analizable? Imo, efectos secundarios en predicados linq = maloliente. – Marc

+0

¿a quién le importa lo que termine siendo? Solo está ahí para permitirme llamar a TryParse. – tster

+0

no le permitiría reemplazar el .Select (str => int.Parse (str)) con .Select (str => i) – JDunkerley

0

O bien se debe tener un delimitador o, que parte debe tener una longitud fija o, la cadena debe seguir un patrónpara el comportamiento de repetición.

+0

No sé qué traerá la cadena de consulta, lo que significa que estoy pasando un valor de cadena de consulta como stringToSplit. Estoy llamando a este método en un valor de cadena de consulta para dividirlo en una lista y depende, a veces puede tener uno, a veces más de uno entrante (dividido por un;) por lo que tengo que dar cuenta de cualquier situación ... 1 o 1 a muchos – PositiveGuy

1

Personalmente, no he probado su código, pero parece funcional. El método Split debería devolver una matriz con un elemento.

Puesto que usted dice que no es, se lo creen, y yo añadiría esto a la parte superior de su método:

if (!stringToSplit.Contains(splitDelimiter)) 
{ 
    int i; 
    if (Int32.TryParse(stringToSplit, out i)) 
     list.Add(i); 
    return list; 
} 
1

No es necesario dar cuenta de esa situación, como string.Split() devuelve una matriz con un solo elemento, cuando no se encuentra ningún delimitador:

If this instance does not contain any of the strings in separator, the returned array consists of a single element that contains this instance.

Ver msdn en "Observaciones"

+0

lo siento, ¿a qué líneas de código se refiere? – PositiveGuy

+0

Ok, pero quiero agregar el valor único a la lista PositiveGuy

+0

¿Así que está diciendo list.Add (string.Split (';')) ?? No sigo – PositiveGuy

1

¿Puedo sugerir un método de extensión para ayudarlo en casos como este en general?

La idea sería yield return todos los resultados de una colección de cadenas que se pueden analizar para un tipo especificado.

En primer lugar se necesitaría un delegado para que coincida con la firma de su norma TryParse método:

public delegate bool Parser<T>(string input, out T value); 

entonces usted puede escribir un método de extensión que tiene una instancia de este tipo de delegado y enumera más de una colección de cadenas , el análisis de todo el mundo que puede:

// Notice: extension methods must belong to a class marked static. 
public static class EnumerableParser 
{ 
    // modified code to prevent horizontal overflow 
    public static IEnumerable<T> ParseAll<T> 
    (this IEnumerable<string> strings, Parser<T> parser) 
    { 
     foreach (string str in strings) 
     { 
      T value; 
      if (parser(str, out value)) 
       yield return value; 
     } 
    } 
} 

Ahora su método StringToList convertido en algo trivial de implementar:

public List<int> StringToList(string stringToSplit, char delimiter) 
{ 
    // Notice: since string.Split returns a string[], and string[] implements 
    // IEnumerable<string>, so the ParseAll extension method can be called on it. 
    return stringToSplit.Split(delimiter).ParseAll<int>(int.TryParse).ToList(); 
} 
+0

Exactamente, esa es la elección natural que tiene el MÁS sentido en términos de capacidad de mantenimiento y reutilización. Sin embargo, BOSS, un dictador hasta incluso querer usar List y me obliga a usar su clase personalizada IntList: List solo para que no tenga que escribir y tampoco quiera usar métodos de extensión (sí, odio este lugar). Si discuto con él, me despedirá. No estoy bromeando. – PositiveGuy

+0

¿Dónde está poniendo ese método para que sea un "método de extensión" y por lo tanto recogido por intellisense como un método fuera de la división? – PositiveGuy

+0

cuando llamaste a ParseAll, veo que solo estás pasando el delegado. Pero, ¿cómo estás pasando las cuerdas param? – PositiveGuy

Cuestiones relacionadas