2012-06-29 9 views
22

Esta pregunta me ha estado molestando durante mucho tiempo pero, en esencia, estoy buscando la forma más eficaz de obtener todas las cadenas entre dos cadenas.Java: ¿la mejor manera de obtener TODAS las cadenas entre dos cadenas? (¿regex?)

La forma en que lo he estado haciendo durante muchos meses ahora es mediante el uso de un montón de índices temporales, cadenas, subcadenas, y es realmente desordenado. ? (¿Por qué Java no tiene un método nativo como String substring(String start, String end)

Digamos que tiene una cadena:.

abcabc [pattern1]foo[pattern2] abcdefg [pattern1]bar[pattern2] morestuff

El objetivo final sería la salida de foo y bar (y más tarde a ser agregados en un JList)

he estado tratando de incorporar expresiones regulares en .split() pero no han tenido éxito. he intentado utilizar la sintaxis * 's y .' s, pero no creo que es bastante lo que mi intención es especialmente ya que .split() solo toma un argumento para dividirse.

De lo contrario, creo que otra forma es utilizar las clases de Patrón y Matcher? Pero estoy muy confuso sobre el procedimiento apropiado.

+0

que debe de utilizar un 'Matcher' para esto. – Amber

+0

@Amber "definitivamente" ?? Ese es un lenguaje bastante fuerte teniendo en cuenta lo que es posible en el código. ¡Vea mi respuesta de una línea (que * no * usa un 'matcher'!) – Bohemian

+0

@Bohemian Y vea mi * comentario * en su respuesta. Solo porque * puedas * usar algo no significa que * debes *. – Amber

Respuesta

59

Es posible construir la expresión regular para hacer esto para usted:

// pattern1 and pattern2 are String objects 
String regexString = Pattern.quote(pattern1) + "(.*?)" + Pattern.quote(pattern2); 

Esto tratará el pattern1 y pattern2 como literal texto, y el texto entre los patrones se captura en el primer capturing group. Puede eliminar Pattern.quote() si desea usar expresiones regulares, pero I no garantiza nada si lo hace.

Puede agregar una cierta personalización de cómo debe ocurrir la coincidencia agregando indicadores al regexString.

  • Si desea entre mayúsculas y minúsculas juego compatibles con Unicode, a continuación, añadir (?iu) al comienzo de regexString, o suministrar Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE bandera para Pattern.compile método.
  • Si quiere capturar el contenido, incluso si las dos cadenas de delimitación aparecen a través de las líneas, a continuación, añadir (?s) antes (.*?), es decir "(?s)(.*?)", o suministrar Pattern.DOTALL bandera para Pattern.compile método.

A continuación, compilar la expresión regular, obtener un objeto Matcher, iterar a través de los partidos y guardarlos en un List (o cualquier Collection, le toca a usted).

Pattern pattern = Pattern.compile(regexString); 
// text contains the full text that you want to extract data 
Matcher matcher = pattern.matcher(text); 

while (matcher.find()) { 
    String textInBetween = matcher.group(1); // Since (.*?) is capturing group 1 
    // You can insert match into a List/Collection here 
} 

código de prueba:

String pattern1 = "hgb"; 
String pattern2 = "|"; 
String text = "sdfjsdkhfkjsdf hgb sdjfkhsdkfsdf |sdfjksdhfjksd sdf sdkjfhsdkf | sdkjfh hgb sdkjfdshfks|"; 

Pattern p = Pattern.compile(Pattern.quote(pattern1) + "(.*?)" + Pattern.quote(pattern2)); 
Matcher m = p.matcher(text); 
while (m.find()) { 
    System.out.println(m.group(1)); 
} 

tenga en cuenta que si se busca el texto entre foo y bar en esta entrada foo text foo text bar text bar con el método anterior, obtendrá un partido, que es  text foo text .

+0

¡Gracias! :) Esto funciona genial! Solo una cosa, la parte 'String textInBetween = m.group (1); // Dado que (. *?) Está capturando el grupo 1 'probablemente debería ser' matcher.group (1) 'pero eso es un error menor y ¡el código de prueba funciona brillantemente! – Justin

+0

@Justin: gracias por detectar el error tipográfico. Copio y pego, pero no pude editar todo. – nhahtdh

+0

@nhahtdh ¡Respuesta muy útil, muchas gracias! –

10

Aquí hay una sola línea que lo hace todo:

List<String> strings = Arrays.asList(input.replaceAll("^.*?pattern1", "") 
    .split("pattern2.*?(pattern1|$)")); 

El desglose es:

  1. Retire todo hasta PATTERN1 (necesario para no terminar con una cadena vacía como el primer término)
  2. Split, en entrada (no expansivo .*?) entre pattern2 y pattern1 (o final de la entrada)
  3. uso del método de utilidad Arrays.asList() para generar una List<String>

Aquí hay algo de código de prueba:

public static void main(String[] args) { 
    String input = "abcabc pattern1foopattern2 abcdefg pattern1barpattern2 morestuff"; 
    List<String> strings = Arrays.asList(input.replaceAll("^.*?pattern1", "").split("pattern2.*?(pattern1|$)")); 
    System.out.println(strings); 
} 

Salida:

[foo, bar] 
+1

Y también es extremadamente difícil de seguir. No me gustaría ver esto en el código que tenía que mantener. – Amber

+0

¿De verdad? Codifiqué esto en un santiamén. De todos modos, solo agregue mi explicación como comentarios dentro del código y todo el mundo estaría feliz – Bohemian

+0

O podría hacerlo usando un Matcher, no tiene que usar comentarios para explicar lo que está sucediendo, y respaldar mejor los futuros cambios potenciales a los requisitos, por ejemplo, su solución se descompone si es conveniente hacer coincidir, dijo, múltiples pares diferentes de marcadores de inicio/final. Usar un matcher tampoco requiere construir una cuerda intermedia, lo que podría tener un aspecto de rendimiento significativo si las cuerdas que se operan son grandes. – Amber

8

Prueba esto:

String str = "its a string with pattern1 aleatory pattern2 things between pattern1 and pattern2 and sometimes pattern1 pattern2 nothing"; 
Matcher m = Pattern.compile(
          Pattern.quote("pattern1") 
          + "(.*?)" 
          + Pattern.quote("pattern2") 
        ).matcher(str); 
while(m.find()){ 
    String match = m.group(1); 
    System.out.println(">"+match+"<"); 
    //here you insert 'match' into the list 
} 

Imprime:

> aleatory < 
> and < 
> < 
+0

¿Qué sucede si quiero que el patrón 1 y el patrón 2 se incluyan en la salida? – R11G

+1

@ R11G puede simplemente concaturar las variables de patrón en la salida, o mover los paréntesis para incluir los patrones: '" ("+ Pattern.quote (pat1) +". *? "+ Pattern.quote (pat2) +") "' y agarrarlo por 'm.group (1)'. – elias

Cuestiones relacionadas