2010-12-21 25 views

Respuesta

11
string source = "the quick brown fox jumps over the lazy dog"; 
string chars = "ogd hte"; 

int? firstNotOf = source.Select((x, i) => new { Val = x, Idx = (int?)i }) 
         .Where(x => chars.IndexOf(x.Val) == -1) 
         .Select(x => x.Idx) 
         .FirstOrDefault(); 

int? lastNotOf = source.Select((x, i) => new { Val = x, Idx = (int?)i }) 
         .Where(x => chars.IndexOf(x.Val) == -1) 
         .Select(x => x.Idx) 
         .LastOrDefault(); 

O, si lo prefiere algunos métodos de extensión no LINQ. Estos deben tener un rendimiento ligeramente mejor, especialmente para FindLastNotOf:

int? firstNotOf = source.FindFirstNotOf(chars); 
int? lastNotof = source.FindLastNotOf(chars); 

// ... 

public static int? FindFirstNotOf(this string source, string chars) 
{ 
    if (source == null) throw new ArgumentNullException("source"); 
    if (chars == null) throw new ArgumentNullException("chars"); 
    if (source.Length == 0) return null; 
    if (chars.Length == 0) return 0; 

    for (int i = 0; i < source.Length; i++) 
    { 
     if (chars.IndexOf(source[i]) == -1) return i; 
    } 
    return null; 
} 

public static int? FindLastNotOf(this string source, string chars) 
{ 
    if (source == null) throw new ArgumentNullException("source"); 
    if (chars == null) throw new ArgumentNullException("chars"); 
    if (source.Length == 0) return null; 
    if (chars.Length == 0) return source.Length - 1; 

    for (int i = source.Length - 1; i >= 0; i--) 
    { 
     if (chars.IndexOf(source[i]) == -1) return i; 
    } 
    return null; 
} 

(Es posible que usted podría obtener un mejor rendimiento - tanto en el LINQ y las versiones no-LINQ - si convierte chars a un HashSet<char>, o tal vez incluso una llanura char[] matriz. que había necesidad de referencia para averiguar, a pesar de cualquier diferencia es probable que sea insignificante a menos chars pone bastante grande.)

+1

Buen trabajo, pero ¿quién en su sano juicio encuentra algo aceptable en una biblioteca o rutina de API? Parece que un MS falla. – GTAE86

4

Si el uso de LINQ es aceptable, puede llamar a los métodos First() y Last() con el predicado apropiado.

Por ejemplo, si desea que los primeros y últimos caracteres que no son vocales:

string vowels = "aeiouy"; 
char first = yourString.First(ch => vowels.IndexOf(ch) < 0); 
char last = yourString.Last(ch => vowels.IndexOf(ch) < 0); 

EDIT: El anterior devolverá los caracteres, no sus índices. Con el fin de hacer eso, se puede proyectar los índices utilizando el método Select(), pero las cosas se ponen peludas, ya que necesitamos para volver -1 si ningún carácter coincide:

int firstIndex = (yourString.Select(
     (ch, i) => new { Character = ch, Index = i } 
    ).First(obj => vowels.IndexOf(obj.Character) < 0) 
    ?? new { Character = '\0', Index = -1 }).Index; 

int lastIndex = (yourString.Select(
     (ch, i) => new { Character = ch, Index = i } 
    ).Last(obj => vowels.IndexOf(obj.Character) < 0) 
    ?? new { Character = '\0', Index = -1 }).Index; 

Alternativamente, he aquí una solución menos complicada basado en @ abatishchev de contestar:

string vowels = "aeiouy"; 
int firstIndex = yourString.IndexOf(yourString.First(
    ch => vowels.IndexOf(ch) < 0)); 
int lastIndex = yourString.LastIndexOf(yourString.Last(
    ch => vowels.IndexOf(ch) < 0)); 
+3

no exactamente: 'find_first_not_of' devuelve la posición, no el carácter. – Vlad

+0

@Vlad, tienes razón, la respuesta se actualizó en consecuencia. Gracias :) –

+3

Creo que LINQ complica mucho las cosas. Y esta solución es muy ineficaz. Estamos creando una gran cantidad de objetos temporales de tipo anónimo junto con iteradores. El método de escritura que simplifica el ciclo será mejor. –

0

he aquí una solución expresión regular.

string testString = "oueytestie"; 
var matchFirstNotOf = Regex.Match(testString, @"[^aeiouy]"); 
int firstNotOf = matchFirstNotOf.Success ? matchFirstNotOf.Index : -1; 
var matchLastNotOf = Regex.Match(testString, @"[^aeiouy]", RegexOptions.RightToLeft); 
int lastNotOf = matchLastNotOf.Success ? matchLastNotOf.Index : -1; 
Cuestiones relacionadas