2012-09-11 11 views
6

¿Cómo puedo verificar si una cadena contiene una subcadena, pero solo en una posición específica?¿Verifica si una cadena contiene una palabra pero solo en una posición específica?

Ejemplo cadena:

¿Cuál es su color favorito ? mi [favorita] color es azul

Si quería comprobar si la cadena contiene una palabra específica que suelo hacer esto:

var 
    S: string; 
begin 
    S := 'What is your favorite color? my [favorite] color is blue'; 
    if (Pos('favorite', S) > 0) then 
    begin 
    // 
    end; 
end; 

Lo que necesito es para determinar si la palabra favorita existe en la cadena, ignorando sin embargo si aparece dentro de los símbolos [], lo que la muestra de código anterior claramente no hace.

Así que si ponemos el código en una función booleana, algunos resultados de la muestra se vería así:

VERDADERO: ¿Cuál es su color favorito ? mi [mi favorito] color es azul

VERDADERO: ¿Cuál es su color favorito ? mi [bla bla] color es azul

FALSO: ¿Cuál es su bla bla color? mi [alguna favorita] color es azul

Las primeras dos muestras anteriores son verdad porque la palabra favorita se encuentra fuera de los símbolos [], ya sea dentro de ellos o no.

La tercera muestra es falsa porque, aunque hay una palabra favorita, solo aparece dentro de los símbolos []; solo debemos verificar si existe fuera de los símbolos.

Necesito una función para determinar si una palabra (favorita en este ejemplo) aparece en una cadena, pero ignorando el hecho si la palabra está rodeada dentro de los símbolos [].

+0

Ideas: 1) Divida la cuerda en el '\ s' y busque el 4º elemento. 2) Verifique 'favorite' (tenga en cuenta los espacios alrededor de la palabra). 3) Divida la cadena en el signo de interrogación '?' Y luego verifique si contiene 'favorite'. –

+5

Buscar '[', si se encuentra la búsqueda ']', eliminar entre-incluyendo '[]', buscar favorito. –

+0

O use una expresión regular (con unidades incluidas en XE) con una expresión regular de ''\ b' + wordtofind + '\ b''. Lo único que tienes que tener en cuenta es '¿Es tu favorito?', Donde el '' 'haría que no coincida. –

Respuesta

8

Me gusta Sertac's idea sobre eliminar cadenas entre corchetes y buscar una cadena después de eso. Aquí está un ejemplo de código extendido por una búsqueda de palabras completas y de mayúsculas y minúsculas:

function ContainsWord(const AText, AWord: string; AWholeWord: Boolean = True; 
    ACaseSensitive: Boolean = False): Boolean; 
var 
    S: string; 
    BracketEnd: Integer; 
    BracketStart: Integer; 
    SearchOptions: TStringSearchOptions; 
begin 
    S := AText; 
    BracketEnd := Pos(']', S); 
    BracketStart := Pos('[', S); 
    while (BracketStart > 0) and (BracketEnd > 0) do 
    begin 
    Delete(S, BracketStart, BracketEnd - BracketStart + 1); 
    BracketEnd := Pos(']', S); 
    BracketStart := Pos('[', S); 
    end; 
    SearchOptions := [soDown]; 
    if AWholeWord then 
    Include(SearchOptions, soWholeWord); 
    if ACaseSensitive then 
    Include(SearchOptions, soMatchCase); 
    Result := Assigned(SearchBuf(PChar(S), StrLen(PChar(S)), 0, 0, AWord, 
    SearchOptions)); 
end; 

Aquí está una versión optimizada de la función, que utiliza puntero iteración carbón sin la manipulación de cadenas. En comparación con una versión anterior, maneja el caso cuando tiene una cadena con un paréntesis de cierre faltante, como por ejemplo My [favorite color is. Tal cadena se evalúa en True debido a ese corchete faltante.

El principio es pasar por toda la cadena char por char y cuando encuentre el soporte de apertura, observe si ese soporte tiene un par de cierre para sí mismo. En caso afirmativo, compruebe si la subcadena de la posición almacenada hasta el paréntesis de apertura contiene la palabra buscada. Si es así, salga de la función. De lo contrario, mueva la posición almacenada al soporte de cierre. Si el paréntesis de apertura no tiene su propio par de cierre, busque la palabra desde la posición almacenada hasta el final de la cadena completa y salga de la función.

Para la versión comentada de este código follow this link.

function ContainsWord(const AText, AWord: string; AWholeWord: Boolean = True; 
    ACaseSensitive: Boolean = False): Boolean; 
var 
    CurrChr: PChar; 
    TokenChr: PChar; 
    TokenLen: Integer; 
    SubstrChr: PChar; 
    SubstrLen: Integer; 
    SearchOptions: TStringSearchOptions; 
begin 
    Result := False; 
    if (Length(AText) = 0) or (Length(AWord) = 0) then 
    Exit; 
    SearchOptions := [soDown]; 
    if AWholeWord then 
    Include(SearchOptions, soWholeWord); 
    if ACaseSensitive then 
    Include(SearchOptions, soMatchCase); 
    CurrChr := PChar(AText); 
    SubstrChr := CurrChr; 
    SubstrLen := 0; 
    while CurrChr^ <> #0 do 
    begin 
    if CurrChr^ = '[' then 
    begin 
     TokenChr := CurrChr; 
     TokenLen := 0; 
     while (TokenChr^ <> #0) and (TokenChr^ <> ']') do 
     begin 
     Inc(TokenChr); 
     Inc(TokenLen); 
     end; 
     if TokenChr^ = #0 then 
     SubstrLen := SubstrLen + TokenLen; 
     Result := Assigned(SearchBuf(SubstrChr, SubstrLen, 0, 0, AWord, 
     SearchOptions)); 
     if Result or (TokenChr^ = #0) then 
     Exit; 
     CurrChr := TokenChr; 
     SubstrChr := CurrChr; 
     SubstrLen := 0; 
    end 
    else 
    begin 
     Inc(CurrChr); 
     Inc(SubstrLen); 
    end; 
    end; 
    Result := Assigned(SearchBuf(SubstrChr, SubstrLen, 0, 0, AWord, 
    SearchOptions)); 
end; 
+1

Gran respuesta, especialmente útil es el enlace a la respuesta con comentarios, hace que sea un poco más fácil de digerir y comprender lo que está sucediendo. –

+1

¡Gracias! De todos modos, Regex es la manera correcta de hacer lo que necesita (y seguramente más fácil), pero por otro lado, esto es más directo solo para esta tarea específica (y más eficiente diría, ya que la expresión regular al menos necesita analizar el la expresión antes comienza a coincidir). Yo diría que si no vas a construir un analizador sintáctico, por ejemplo, donde tendrías muchas tareas similares como esta coincidencia, entonces esta solución podría ser más ligera que incluir expresiones regulares. Pero la razón principal por la que publiqué esto es que ninguna de las respuestas aquí usaba Delphi puro. – TLama

7

En regular expressions, hay una cosa llamada look-around que puede usar. En su caso, puede resolverlo con un lookbehind negativo: desea "favorito" a menos que esté precedido por un corchete de apertura. Se podría tener este aspecto:

(?<!\[[^\[\]]*)favorite 

Paso a paso: (?<! es el prefijo de búsqueda hacia atrás negativo, estamos buscando \[ opcionalmente seguido por ninguno o más cosas que no están cerrando o abriendo paréntesis: [^\[\]]*, cierre la negativa Mire detrás con ), y luego favorite inmediatamente después.

+0

Creo que la suya es una solución elegante y adecuada – diegoaguilar

0

Creo que puede reformular su problema como "encontrar una ocurrencia de la cadena proporcionada no rodeada de corchetes". Si eso describe su problema, puede continuar y usar una expresión regular simple como [^\[]favorite[^\]].

Cuestiones relacionadas