Hay un medio para obtener el índice de la primera no-carácter de espacio en blanco en una cadena (o, más en general, el índice del primer carácter de la coincidencia de una condición) en C# sin escribir mi propio código bucle?

EDITAR

Por «escribir mi propio código bucle», yo en realidad quería decir que estoy buscando una compacta expresión que resuelve el problema sin estorbar la lógica en el que estoy trabajando.

Pido disculpas por cualquier confusión sobre este punto.

  • Está usted familiarizado con la Expresión regular?
  • Sí, pero, francamente, me tienden a evitarlas. Probablemente excesivo sesgo derivados del hecho de que me han tendido a trabajar en rendimiento crítico código en mi carrera y un RegEx no suele ser la solución más rápida. Concedido, a veces puede ser la mejor solución en una situación dada.
  • Mi respuesta es la más corta y sencilla solución. int pos = myString.ToList<char>().FindIndex(x => char.IsWhiteSpace(x) == false);
InformationsquelleAutor Eric J. | 2012-10-02

11 Comentarios

  1. 13

    Me gusta definir mi propio método de extensión para devolver el índice del primer elemento que cumple una costumbre predicado en una secuencia.

    ///<summary>
    ///Returns the index of the first element in the sequence 
    ///that satisfies a condition.
    ///</summary>
    ///<typeparam name="TSource">
    ///The type of the elements of <paramref name="source"/>.
    ///</typeparam>
    ///<param name="source">
    ///An <see cref="IEnumerable{T}"/> that contains
    ///the elements to apply the predicate to.
    ///</param>
    ///<param name="predicate">
    ///A function to test each element for a condition.
    ///</param>
    ///<returns>
    ///The zero-based index position of the first element of <paramref name="source"/>
    ///for which <paramref name="predicate"/> returns <see langword="true"/>;
    ///or -1 if <paramref name="source"/> is empty
    ///or no element satisfies the condition.
    ///</returns>
    public static int IndexOf<TSource>(this IEnumerable<TSource> source, 
        Func<TSource, bool> predicate)
    {
        int i = 0;
    
        foreach (TSource element in source)
        {
            if (predicate(element))
                return i;
    
            i++;
        }
    
        return -1;
    }

    Usted podría utilizar LINQ para abordar su problema original:

    string str = "   Hello World";
    int i = str.IndexOf<char>(c => !char.IsWhiteSpace(c));
    • Yo estaba pensando método de extensión para el bucle. Me gusta tu generalización de la idea.
    • no estoy tratando de ser polémico por decir esto, pero pensé que el punto de la cuestión es cómo hacerlo sin necesidad de escribir un bucle para esto como la respuesta está tirando de mí en off (de nuevo, no se queja – sólo por curiosidad)
    • Puedo definir de forma genérica ya que tienden a utilizar en varios otros escenarios.
    • Sí, pero yo no lo veo una solución mejor que la escritura de un método de extensión. Me disculpo si fui claro.
    • Punto válido, pero yo lo interpretó más liberal en el sentido de que el OP no quiere escribir un bucle cada vez que él/ella necesita para obtener el índice del primer carácter que se cumpla una condición. Prácticamente todos de LINQ es escrito usando bucles internamente; se puede pensar en la de arriba como la de otro LINQ método que fue omitido en la versión original.
    • Pero creo que el nombre (Porcentaje) es un poco dudoso ya que String ya tiene uno con el mismo nombre.
    • Por qué? Proporciona un equivalente genérico que es más flexible. str.IndexOf(...) utilizará la versión no genérica se define en el marco (y he editado la respuesta a la llamada de la versión genérica 🙂
    • La manera en que yo lo veo, mi método de la semántica es una generalización de String.IndexOf, por lo que es aceptable para aparecer como otro de sobrecarga.
    • Sí, supongo que es aceptable y por suerte la <char> no es necesario. Todavía un nombre como IndexOfWhere() podría ser más clara.
    • Justo lo suficiente. No me importa tener mis métodos comparten el mismo nombre de la biblioteca, pero puedo entender a los demás que sería la mente.

  2. 36

    Un string es, por supuesto, un IEnumerable<char> así que usted puede utilizar Linq:

    int offset = someString.TakeWhile(c => char.IsWhiteSpace(c)).Count();
    • este es mi favorito personal – muy a punto, y claro
    • +1, que es elegante.
    • Creo que podría coincidir con el marco de la semántica mejor si devuelve -1 en caso de error (es decir, cuando la cadena está vacía, o sólo consiste en caracteres de espacios en blanco).
    • Resharper sugiere: someString.Y takewhile(char.IsWhiteSpace).Count();
  3. 4
    string s= "   \t  Test";
    Array.FindIndex(s.ToCharArray(), x => !char.IsWhiteSpace(x));

    devuelve 6

    Para agregar una condición acaba de hacer …

    Array.FindIndex(s.ToCharArray(), x => !char.IsWhiteSpace(x) && your condition);
    • +1, que es una alternativa muy interesante yo no era consciente.
  4. 3
    var match = Regex.Match(" \t test  ", @"\S"); //\S means all characters that are not whitespace
    if (match.Success)
    {
        int index = match.Index;
        //do something with index
    }
    else
    {
        //there were no non-whitespace characters, handle appropriately
    }

    Si usted va a hacer esto a menudo, por razones de rendimiento se debe almacenar en caché el compilado Regex de este patrón, por ejemplo:

    static readonly Regex nonWhitespace = new Regex(@"\S");

    A continuación, utilizar como:

    nonWhitespace.Match(" \t test  ");
    • Funciona, pero en realidad más código de un bucle :-).
    • Aunque el uso de expresiones regulares (RegEx es una buena solución perfectamente válida, siempre evite el uso de ellos cuando hay un más fácil construido en solución. RegEx son naturalmente fuertes en términos de rendimiento.
    • usted podría reducir a dos líneas con var index = match.Success ? match.Index : -1; (o (int?)null o default(int?) si prefieres null más de -1 para un no-partido). @lcfseth buen punto. El autor de la pregunta no quiso bucle, y «de manera más general, el índice del primer carácter de la coincidencia de una condición», que se parece más a regex que no. Para algo tan simple como «espacio en blanco» yo estaría de acuerdo con usted, pero esto podría ser útil en otros casos.
  5. 3

    Puede utilizar el De la cadena.IndexOfAny función que devuelve la primera ocurrencia de cualquier carácter en una matriz especificada de caracteres Unicode.

    Como alternativa, puede utilizar la De la cadena.TrimStart función que quitar todos los caracteres de espacio en blanco desde el principio de la cadena. El índice de la primera no-carácter de espacio en blanco es la diferencia entre la longitud de la cadena original y el tapizado en uno.

    Usted puede incluso seleccionar un conjunto de caracteres para recortar 🙂

    Básicamente, si usted está buscando para un conjunto limitado de caracteres (digamos dígitos), usted debe ir con el primer método.

    Si usted está tratando de ignorar a un conjunto limitado de caracteres (como los espacios en blanco), usted debe ir con el segundo método.

    Un Último método sería utilizar el Linq métodos:

    string s = "        qsdmlkqmlsdkm";
    Console.WriteLine(s.TrimStart());
    Console.WriteLine(s.Length - s.TrimStart().Length);
    Console.WriteLine(s.FirstOrDefault(c => !Char.IsWhiteSpace(c)));
    Console.WriteLine(s.IndexOf(s.FirstOrDefault(c => !Char.IsWhiteSpace(c))));

    De salida:

    qsdmlkqmlsdkm
    8
    q
    8
    • Pero eso requiere una matriz de todos los no-espacios en blanco caracteres…
    • El recorte de métodos que pueden ser llamados sin parámetros y en este caso se va a eliminar todos los espacios en blanco. Como para la consulta de linq, puede utilizar el IsWhiteSpace función. Voy a actualizar el código de ejemplo.
  6. 3

    Ya que hay varias soluciones aquí me decidí a hacer algunas pruebas de rendimiento para ver cómo cada uno realiza. Decidido compartir estos resultados para los interesados…

    Resultados están en milisegundos….

    Donde s = «\t Test»

    Convertir a la matriz de char y el uso FindIndex: 154

    Recorte de espacios y obtener el índice del primer carácter: 189

    El uso del método de extensión: 234

    Loop: 146

    Donde s = «Prueba»

    Convertir a la matriz de char y el uso FindIndex: 39

    Recorte de espacios y obtener el índice del primer carácter: 155

    El uso del método de extensión: 57

    Loop: 15

    Donde s = (1000 cadena de caracteres sin espacios)

    Convertir a la matriz de char y el uso FindIndex: 506

    Recorte de espacios y obtener el índice del primer carácter: 534

    El uso del método de extensión: 51

    Loop: 15

    Donde s = (1000 cadena de caracteres que comienza con «\t Test»)

    Convertir a la matriz de char y el uso FindIndex: 609

    Recorte de espacios y obtener el índice del primer carácter: 1103

    El uso del método de extensión: 226

    Loop: 146

    Sacar sus propias conclusiones, pero mi conclusión es que el uso de lo que uno
    te gusta el mejor, debido a las diferencias de rendimiento es insignificante en
    mundo real escenarios.

  7. 1

    Puede recortar, obtener el primer carácter y el uso IndexOf.

    • No muy potente, pero hace el truco.
    • Recorte crea una copia de la cadena. No es ideal, pero funcional.
    • Mejor uso de TrimStart y ver cuánto más corta es la cadena resultante es. Todavía se crea una copia.
    • J., que es la razón por la que me dijo que esto no es la mejor solución. Pero es simple y puede ser envuelto en un método de extensión. Hay un montón de soluciones de aquí que también son buenos (y probablemente elegiría el uno con el mejor legibilidad)
    • tiene usted razón!
    • Ama a sí mismo comentario :). Una vez que haya trimed de la cadena desde el inicio el uso de la StartTrim función, usted sólo tiene que tomar la diferencia entre las dos longitudes para obtener el índice.
    • Incluso si utiliza linq, una copia será creado.

  8. 1

    Hay una solución muy simple

    pos va a ser de 4

    usted puede tener condiciones más complejas como:

    • Usted puede acortar este a return (x == 's');
  9. 0

    Sí puedes intentar esto:

    • Que crea una copia de la cadena. No es ideal en términos de eficiencia.
  10. 0

    Algo va a ser un bucle en algún lugar. Para el control completo sobre lo que es y no es el espacio en blanco que usted podría utilizar linq to objects para hacer el bucle:

    • .NET define lo que es y no es el espacio en blanco msdn.microsoft.com/en-us/library/t809ektx.aspx. No se alejen de esa definición, sin un dominio de la razón específica para hacerlo.
    • Sí, estoy de acuerdo, acabo de aprender a partir de este hilo, gracias!
  11. 0

    Hay un montón de soluciones que convertir la cadena en una matriz. Que no es necesario, caracteres individuales de una cadena que se puede acceder así como de elementos de una matriz.

    Esta es mi solución, que debe ser muy eficiente:

    Y el uso de estos, hacer lo siguiente:

Dejar respuesta

Please enter your comment!
Please enter your name here