Bagaimana menemukan kemunculan karakter ke-n dalam sebuah string?

95

Mirip dengan pertanyaan yang diposting di sini , saya mencari solusi di Java.

Artinya, bagaimana menemukan indeks kemunculan n dari sebuah karakter / string dari sebuah string?

Contoh: " / folder1 / folder2 / folder3 / ". Dalam kasus ini, jika saya meminta kemunculan ketiga garis miring (/), itu muncul sebelum folder3, dan saya berharap untuk mengembalikan posisi indeks ini. Niat sebenarnya saya adalah untuk mensubstringinya dari kemunculan n karakter.

Apakah ada metode nyaman / siap pakai yang tersedia di Java API atau apakah kita perlu menulis logika kecil sendiri untuk menyelesaikan ini?

Juga,

  1. Saya dengan cepat mencari apakah ada metode yang didukung untuk tujuan ini di StringUtils Apache Commons Lang , tetapi saya tidak menemukannya.
  2. Dapatkah ekspresi reguler membantu dalam hal ini?
Gnanam
sumber
2
Untuk contoh khusus Anda, bergantung pada apa yang ingin Anda lakukan dengan hasilnya, mungkin lebih mudah untuk membagi string pada /, yang mungkin memberi Anda apa yang Anda butuhkan secara langsung?
Pola Dasar Paul
@ Paul: Itu ide yang bagus juga.
Gnanam

Jawaban:

128

Jika proyek Anda sudah bergantung pada Apache Commons, Anda dapat menggunakan StringUtils.ordinalIndexOf, jika tidak, berikut implementasinya:

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;
}

Posting ini telah ditulis ulang sebagai artikel di sini .

aioobe
sumber
Terlepas dari kesalahan "off-by-one", ada hal positif lainnya dalam solusi @Jon Skeet - Dengan sedikit perubahan (membalikkan loop), Anda juga dapat memiliki "kejadian n dari yang terakhir".
Karan Chadha
@KaranChha, hal yang sama berlaku untuk solusi ini. Ganti saja ke lastIndexOf.
aioobe
60

Saya percaya solusi termudah untuk menemukan kejadian N dari String adalah dengan menggunakan StringUtils.ordinalIndexOf () dari Apache Commons.

Contoh:

StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  == 5
Al Belsky
sumber
27

Dua opsi sederhana terjadi:

  • Gunakan charAt()berulang kali
  • Gunakan indexOf()berulang kali

Sebagai contoh:

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;
}

Itu mungkin tidak berfungsi sebaik penggunaan indexOfberulang kali, tetapi mungkin lebih mudah untuk melakukannya dengan benar.

Jon Skeet
sumber
15

Anda dapat mencoba sesuatu seperti ini:

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;
    }
}

Perhatikan bahwa saya melakukan beberapa asumsi di regex:

  • jalur input adalah absolut (yaitu dimulai dengan "/");
  • Anda tidak perlu "/" ke-3 pada hasil.

Seperti yang diminta dalam komentar, saya akan mencoba menjelaskan regex: (/[^/]*){2}/([^/]*)

Visualisasi ekspresi reguler

  • /[^/]*adalah /diikuti oleh [^/]*(sejumlah karakter yang tidak /),
  • (/[^/]*)mengelompokkan ekspresi sebelumnya dalam satu entitas. Ini adalah 1kelompok ekspresi pertama,
  • (/[^/]*){2}artinya grup tersebut harus sama persis dengan {2}waktu,
  • [^/]*lagi-lagi sejumlah karakter yang bukan /,
  • ([^/]*)mengelompokkan ekspresi previos dalam satu entitas. Ini adalah 2grup ekspresi nd.

Dengan cara ini Anda hanya perlu mendapatkan substring yang cocok dengan grup ke-2: return m.group(2);

Gambar milik Debuggex

andcoz
sumber
1
bisakah Anda menjelaskan regex dalam bahasa Inggris biasa? Seperti: Garis miring terbalik diikuti oleh apa pun yang bukan garis miring terbalik dalam waktu yang tidak terbatas ... Maka saya tidak yakin.
Menyerahkan
1
@Ced, saya menambahkan penjelasan dan perbaikan kecil untuk regex. Saya harap sekarang lebih jelas.
andcoz
Terima kasih telah menjelaskan regex.
Vishwa Ratna
8

Saya membuat beberapa perubahan pada jawaban aioobe dan mendapatkan versi IndexOf terakhir ke-n, dan memperbaiki beberapa masalah NPE. Lihat kode di bawah ini:

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;
}
Bodoh
sumber
3
Saya pikir masuk akal bahwa metode ini melempar NPE jika diberikan nullsebagai argumen. Ini adalah perilaku paling umum di pustaka standar.
aioobe
5
 ([.^/]*/){2}[^/]*(/)

Cocokkan apa saja diikuti dengan / dua kali, lalu lagi. Yang ketiga adalah yang Anda inginkan

The Matcher negara dapat digunakan untuk mengatakan di mana / terakhir adalah

Pola Dasar Paul
sumber
Saya yakin ini adalah jawaban yang sangat keren, tetapi bagaimana cara menggunakan ini dalam kode saya?
ARK
Lihatlah jawaban @ andcoz (regexp berbeda, tetapi idenya sama)
The Archetypal Paul
3
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;
}
Saul
sumber
3

Saat ini ada dukungan dari StringUtils Apache Commons Lang ,

Ini yang primitif:

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

untuk masalah Anda, Anda dapat membuat kode berikut: StringUtils.ordinalIndexOf(uri, "/", 3)

Anda juga dapat menemukan kemunculan terakhir karakter dalam string dengan metode lastOrdinalIndexOf .

Chexpir
sumber
3

Mungkin Anda bisa mencapai ini melalui metode String.split (..) juga.

String str = "";
String[] tokens = str.split("/")
return tokens[nthIndex] == null 
Murali
sumber
2

Pendekatan lain:

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);
}
Marimuthu Madasamy
sumber
2

Jawaban ini menyempurnakan jawaban @aioobe. Dua bug dalam jawaban itu telah diperbaiki.
1. n = 0 harus mengembalikan -1.
2. kemunculan n kembali -1, tapi bekerja pada kemunculan n-1.

Coba ini !

    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;
}
TABUT
sumber
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;
        }
    }
}
SAN
sumber
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;
        }
    }
}
Mawar
sumber
0

Solusi saya:

/**
 * 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;
}
Per Lindberg
sumber
0

Kode mengembalikan substring posisi kejadian ke-n alias lebar bidang. Contoh. Jika string "Stack overflow in low melow" adalah string untuk mencari kejadian kedua dari token "low", Anda akan setuju dengan saya bahwa itu adalah kejadian kedua pada subtring "18 dan 21" . indexOfOccurance ("Stack overflow in low melow", low, 2) mengembalikan 18 dan 21 dalam sebuah string.

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));
    }
    }

sumber
0
public static int findNthOccurrence(String phrase, String str, int n)
{
    int val = 0, loc = -1;
    for(int i = 0; i <= phrase.length()-str.length() && val < n; i++)
    {
        if(str.equals(phrase.substring(i,i+str.length())))
        {
            val++;
            loc = i;
        }
    }

    if(val == n)
        return loc;
    else
        return -1;
}
wess
sumber
2
Meskipun kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah akan sangat membantu meningkatkan kualitas posting Anda, dan mungkin menghasilkan lebih banyak suara. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang. Harap edit jawaban Anda untuk menambahkan penjelasan dan memberikan indikasi batasan dan asumsi apa yang berlaku.
Pika the Wizard of the Whales
0

// scala

// throw's -1 jika nilainya tidak ada untuk ke n kali, bahkan jika ada sampai n-1st time. // throw's index jika nilainya ada untuk ke-n kalinya

def indexOfWithNumber(tempString:String,valueString:String,numberOfOccurance:Int):Int={
var stabilizeIndex=0 
var tempSubString=tempString 
var tempIndex=tempString.indexOf(valueString) 
breakable
{
for ( i <- 1 to numberOfOccurance)
if ((tempSubString.indexOf(valueString) != -1) && (tempIndex != -1))
{
tempIndex=tempSubString.indexOf(valueString)
tempSubString=tempSubString.substring(tempIndex+1,tempSubString.size) // ADJUSTING FOR 0
stabilizeIndex=stabilizeIndex+tempIndex+1 // ADJUSTING FOR 0
}
else
{ 
stabilizeIndex= -1
tempIndex= 0
break
}
}
stabilizeIndex match { case value if value <= -1 => -1 case _ => stabilizeIndex-1 } // reverting for adjusting 0 previously
}


indexOfWithNumber("bbcfgtbgft","b",3) // 6
indexOfWithNumber("bbcfgtbgft","b",2) //1
indexOfWithNumber("bbcfgtbgft","b",4) //-1

indexOfWithNumber("bbcfgtbcgft","bc",1)  //1
indexOfWithNumber("bbcfgtbcgft","bc",4) //-1
indexOfWithNumber("bbcfgtbcgft","bc",2) //6
Raptor0009
sumber