2010-10-20 19 views
74

Similar a una pregunta publicada here, estoy buscando para una solución en Java.¿Cómo encontrar nth aparición de carácter en una cadena?

Es decir, ¿cómo encontrar el índice de enésima ocurrencia de un carácter/cadena de una cadena?

Ejemplo: "/carpeta1/carpeta2/carpeta3/". En este caso, si solicito la 3ra aparición de barra inclinada (/), aparece antes de la carpeta 3, y espero devolver esta posición de índice. Mi intención real es subscribirlo desde la enésima ocurrencia de un personaje.

¿Hay algún método conveniente/listo para usar disponible en la API de Java o necesitamos escribir una pequeña lógica nosotros solos para resolver esto?

Además,

  1. rápidamente me han buscado si se admite cualquier método para este fin en Apache Commons Lang StringUtils, pero no encuentro ninguna.
  2. ¿Pueden las expresiones regulares ayudar a este respecto?
+2

Para su ejemplo particular, dependiendo de lo que quiera hacer con el resultado, ¿podría ser más fácil dividir la cadena en /, lo que bien podría darle lo que necesita directamente? –

+0

@Paul: Esa es una buena idea también. – Gnanam

Respuesta

25

dos opciones simples ocurren:

  • Uso charAt() repetidamente
  • Uso indexOf() repetidamente

Por ejemplo:

public static int nthIndexOf(String text, char needle, int n) 
{ 
    for (int i = 0; i < text.length(); i++) 
    { 
     if (text.charAt(i) == needle) 
     { 
      n--; 
      if (n == 0) 
      { 
       return i; 
      } 
     } 
    } 
    return -1; 
} 

que bien puede no funcionar tan bien como tu cantar indexOf en varias ocasiones, pero posiblemente sea más sencillo hacerlo bien.

5
([.^/]*/){2}[^/]*(/) 

Empareje cualquier cosa seguida por/dos veces, luego otra vez. La tercera es la que desea

El estado Matcher se puede utilizar para decir donde el último/es

+0

Estoy seguro de que esta es una respuesta muy buena, pero ¿cómo uso esto en mi código? –

+0

Mire la respuesta de @ andcoz (expresiones regulares diferentes, pero la idea es la misma) –

110

Si su proyecto ya depende de Apache Commons puede utilizar StringUtils.ordinalIndexOf, de lo contrario, aquí está una implementación:

public static int ordinalIndexOf(String str, String substr, int n) { 
    int pos = str.indexOf(substr); 
    while (--n > 0 && pos != -1) 
     pos = str.indexOf(substr, pos + 1); 
    return pos; 
} 

Este post ha sido reescrito como un artículo here.

+0

Además del error "uno por uno", hay otra gran ventaja en la solución de @Jon Skeet: con un pequeño ajuste (invirtiendo el ciclo) , también puedes tener la "enésima ocurrencia de la última". –

+0

@KaranChadha, lo mismo se aplica en esta solución. Simplemente cambie a ['lastIndexOf'] (https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#lastIndexOf%28java.lang.String,%20int%29). – aioobe

2
public static int nth(String source, String pattern, int n) { 

    int i = 0, pos = 0, tpos = 0; 

    while (i < n) { 

     pos = source.indexOf(pattern); 
     if (pos > -1) { 
     source = source.substring(pos+1); 
     tpos += pos+1; 
     i++; 
     } else { 
     return -1; 
     } 
    } 

    return tpos - 1; 
} 
14

Usted puede intentar algo como esto:

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class Main { 
    public static void main(String[] args) { 
     System.out.println(from3rd("/folder1/folder2/folder3/")); 
    } 

    private static Pattern p = Pattern.compile("(/[^/]*){2}/([^/]*)"); 

    public static String from3rd(String in) { 
     Matcher m = p.matcher(in); 

     if (m.matches()) 
      return m.group(2); 
     else 
      return null; 
    } 
} 

Nota que hice algunas suposiciones en la expresión regular:

  • el camino de entrada es absoluta (es decir, comienza con "/") ;
  • no necesita el 3er "/" en el resultado.

Como se pide en un comentario, voy a tratar de explicar la expresión regular: (/[^/]*){2}/([^/]*)

Regular expression visualization

  • /[^/]* es una / seguido por [^/]* (cualquier número de caracteres que se no es /),
  • (/[^/]*) grupos th e expresión previa en una sola entidad. Este es el grupo 1 st de la expresión,
  • (/[^/]*){2} significa que el grupo debe coincidir con extactly {2} veces,
  • [^/]* es nuevo en cualquier número de caracteres que no son un /,
  • ([^/]*) grupos de la expresión Previos en una entidad única. Este es el 2 nd grupo de la expresión.

De esta manera sólo tiene que conseguir la subcadena que coincide con el segundo grupo: return m.group(2);

Imagen cortesía por Debuggex

+1

¿podría explicar la expresión regular en inglés sencillo? Me gusta: una barra invertida seguida de cualquier cosa que no sea un backslach un tiempo indefinido ... Entonces no estoy seguro. – Ced

+1

@Ced, agregué una explicación y una pequeña corrección para regex. Espero que esté más claro ahora. – andcoz

+0

Eso fue muy claro, gracias. – Ced

2

Otro enfoque:

public static void main(String[] args) { 
    String str = "/folder1/folder2/folder3/"; 
    int index = nthOccurrence(str, '/', 3); 
    System.out.println(index); 
} 

public static int nthOccurrence(String s, char c, int occurrence) { 
    return nthOccurrence(s, 0, c, 0, occurrence); 
} 

public static int nthOccurrence(String s, int from, char c, int curr, int expected) { 
    final int index = s.indexOf(c, from); 
    if(index == -1) return -1; 
    return (curr + 1 == expected) ? index : 
     nthOccurrence(s, index + 1, c, curr + 1, expected); 
} 
50

creo que la solución más fácil para encontrar la enésima aparición de una Cadena es usar StringUtils.ordinalIndexOf() de Apache Commons.

Ejemplo:

StringUtils.ordinalIndexOf("aabaabaa", "b", 2) == 5 
8

Hice algunos cambios para aioobe de respuesta y tiene una versión lastIndexOf enésimo, y corregir algunos problemas NPE. Ver código de abajo:

public int nthLastIndexOf(String str, char c, int n) { 
     if (str == null || n < 1) 
      return -1; 
     int pos = str.length(); 
     while (n-- > 0 && pos != -1) 
      pos = str.lastIndexOf(c, pos - 1); 
     return pos; 
} 
+1

Creo que es razonable que el método arroje un NPE si se le da 'null' como argumento. Este es el comportamiento más común en la biblioteca estándar. – aioobe

0
/* program to find nth occurence of a character */ 

import java.util.Scanner; 

public class CharOccur1 
{ 

    public static void main(String arg[]) 
    { 
     Scanner scr=new Scanner(System.in); 
     int position=-1,count=0; 
     System.out.println("enter the string"); 
     String str=scr.nextLine(); 
     System.out.println("enter the nth occurence of the character"); 
     int n=Integer.parseInt(scr.next()); 
     int leng=str.length(); 
     char c[]=new char[leng]; 
     System.out.println("Enter the character to find"); 
     char key=scr.next().charAt(0); 
     c=str.toCharArray(); 
     for(int i=0;i<c.length;i++) 
     { 
      if(c[i]==key) 
      { 
       count++; 
       position=i; 
       if(count==n) 
       { 
        System.out.println("Character found"); 
        System.out.println("the position at which the " + count + " ocurrence occurs is " + position); 
        return; 
       } 
      } 
     } 
     if(n>count) 
     { 
      System.out.println("Character occurs "+ count + " times"); 
      return; 
     } 
    } 
} 
-1

// en C++ puro

int pos = 0; 
for (int i = 0; i < N; ++i) // N = nth position 
{ 
    pos = STRING.find(delim, pos + size_of_delim); 
} 
3

Hoy en día existe un apoyo de la StringUtils,

Esta es la primitiva Apache Commons Lang:

int org.apache.commons.lang.StringUtils.ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) 

para su problema puede codificar el siguiente: StringUtils.ordinalIndexOf(uri, "/", 3)

también se puede encontrar el último enésima aparición de un carácter en una cadena con el método lastOrdinalIndexOf.

1
public class Sam_Stringnth { 

    public static void main(String[] args) { 
     String str="abcabcabc"; 
     int n = nthsearch(str, 'c', 3); 
     if(n<=0) 
      System.out.println("Character not found"); 
     else 
      System.out.println("Position is:"+n); 
    } 
    public static int nthsearch(String str, char ch, int n){ 
     int pos=0; 
     if(n!=0){ 
      for(int i=1; i<=n;i++){ 
       pos = str.indexOf(ch, pos)+1; 
      } 
      return pos; 
     } 
     else{ 
      return 0; 
     } 
    } 
} 
2

Responde mejor que la respuesta de @aioobe. Se corrigieron dos errores en esa respuesta.
1. n = 0 debería devolver -1.
2. nth occurrence devolvió -1, pero funcionó en n-1º ocurrencias.

¡Pruebe esto!

public int nthOccurrence(String str, char c, int n) { 
    if(n <= 0){ 
     return -1; 
    } 
    int pos = str.indexOf(c, 0); 
    while (n-- > 1 && pos != -1) 
     pos = str.indexOf(c, pos+1); 
    return pos; 
} 
0

Mi solución:

/** 
* Like String.indexOf, but find the n:th occurance of c 
* @param s string to search 
* @param c character to search for 
* @param n n:th character to seach for, starting with 1 
* @return the position (0-based) of the found char, or -1 if failed 
*/ 

public static int nthIndexOf(String s, char c, int n) { 
    int i = -1; 
    while (n-- > 0) { 
     i = s.indexOf(c, i + 1); 
     if (i == -1) 
      break; 
    } 
    return i; 
} 
0

El código devuelve las posiciones enésima aparición de subcadenas aka ancho de campo. Ejemplo. si cadena "Desbordamiento de pila en bajo melow" es la cadena para buscar 2da ocurrencia de token "bajo", usted estará de acuerdo conmigo en que la segunda aparición es en la subcadena "18 y 21". indexOfOccurance ("Desbordamiento de pila en baja melow", baja, 2) devuelve 18 y 21 en una cadena.

class Example{ 
    public Example(){ 
    } 
      public String indexOfOccurance(String string, String token, int nthOccurance) { 
        int lengthOfToken = token.length(); 
        int nthCount = 0; 
        for (int shift = 0,count = 0; count < string.length() - token.length() + 2; count++, shift++, lengthOfToken++) 
         if (string.substring(shift, lengthOfToken).equalsIgnoreCase(token)) { 
        // keeps count of nthOccurance 
          nthCount++; 
         if (nthCount == nthOccurance){ 
        //checks if nthCount == nthOccurance. If true, then breaks 
          return String.valueOf(shift)+ " " +String.valueOf(lengthOfToken); 
         } 
        } 
        return "-1"; 
       } 
    public static void main(String args[]){ 
    Example example = new Example(); 
    String string = "the man, the woman and the child"; 
    int nthPositionOfThe = 3; 
    System.out.println("3rd Occurance of the is at " + example.indexOfOccurance(string, "the", nthPositionOfThe)); 
    } 
    } 
0

Puede ser que pueda lograr esto a través del método String.split (..) también.

String str = ""; 
String[] tokens = str.split("/") 
return tokens[nthIndex] == null 
Cuestiones relacionadas