Bir dizede n'inci karakter oluşumu nasıl bulunur?


95

Burada yayınlanan bir soruya benzer şekilde , Java'da bir çözüm arıyorum.

Yani, bir dizeden bir karakter / dizenin n'inci oluşum dizini nasıl bulunur?

Örnek: " / klasör1 / klasör2 / klasör3 / ". Bu durumda, eğik çizginin (/) 3. oluşumunu istersem, klasör3'ten önce görünür ve bu dizin konumunu döndürmeyi bekliyorum. Gerçek niyetim, onu bir karakterin n.

Java API'de herhangi bir uygun / kullanıma hazır yöntem var mı yoksa bunu çözmek için kendi başımıza küçük bir mantık yazmamız mı gerekiyor?

Ayrıca,

  1. Apache Commons Lang's StringUtils'te bu amaç için herhangi bir yöntemin desteklenip desteklenmediğini hızlı bir şekilde araştırdım , ancak bulamadım.
  2. Normal ifadeler bu konuda yardımcı olabilir mi?

2
Özel örneğiniz için, sonuçla ne yapmak istediğinize bağlı olarak, dizeyi / üzerine bölmek daha kolay olabilir, bu da size doğrudan ihtiyacınız olanı verebilir?
The Archetypal Paul

@Paul: Bu da iyi bir fikir.
Gnanam

Yanıtlar:


131

Projeniz zaten Apache Commons'a bağlıysa kullanabilirsiniz StringUtils.ordinalIndexOf, aksi takdirde burada bir uygulama vardır:

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

Bu gönderi burada bir makale olarak yeniden yazılmıştır .


"Off-by-one" hatasından ayrı olarak, @Jon Skeet'in çözümünde başka bir büyük pozitif daha var - Küçük bir ince ayar ile (döngüyü tersine çevirerek), "sondan n'inci oluşum" da elde edebilirsiniz.
Karan Chadha

@KaranChadha, bu çözüm için de aynı şey geçerli. Sadece olarak değiştirin lastIndexOf.
aioobe


28

İki basit seçenek oluşur:

  • charAt()Tekrar tekrar kullanın
  • indexOf()Tekrar tekrar kullanın

Örneğin:

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

Bu, indexOftekrar tekrar kullanmak kadar iyi performans göstermeyebilir , ancak muhtemelen doğru yapmak daha kolaydır.


15

Bunun gibi bir şey deneyebilirsiniz:

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

Normal ifadede bazı varsayımlar yaptığımı unutmayın:

  • giriş yolu mutlaktır (yani "/" ile başlar);
  • sonuçta 3. "/" işaretine ihtiyacınız yoktur.

Bir yorumda istendiği gibi, normal ifadeyi açıklamaya çalışacağım: (/[^/]*){2}/([^/]*)

Düzenli ifade görselleştirme

  • /[^/]*Bir edilir /ve ardından [^/]*, (a olmayan, herhangi bir karakter sayısı /),
  • (/[^/]*)önceki ifadeyi tek bir varlıkta gruplandırır. Bu, 1ifadenin birinci grubudur,
  • (/[^/]*){2}grubun tam olarak eşleşmesi gerektiği anlamına gelir {2},
  • [^/]*yine a olmayan herhangi bir sayıda karakterdir /,
  • ([^/]*)önceki ifadeyi tek bir varlıkta gruplandırır. Bu, 2ifadenin nd grubudur.

Bu şekilde yalnızca 2. grupla eşleşen alt dizeyi almanız gerekir: return m.group(2);

Görüntü Debuggex tarafından sağlanmıştır


1
normal ifadeyi düz ingilizce olarak açıklayabilir misin? Mesela: Ters eğik çizgi ve arkasından sonsuz sayıda geri eğik çizgi olmayan herhangi bir şey geliyor ... O zaman emin değilim.
Ced

1
@Ced, regex'e bir açıklama ve küçük bir düzeltme ekledim. Umarım şimdi daha nettir.
andcoz

Normal ifadeyi açıkladığınız için teşekkürler.
Vishwa Ratna

8

Aioobe'nin cevabında birkaç değişiklik yaptım ve n'inci lastIndexOf sürümünü edindim ve bazı NPE sorunlarını düzelttim. Aşağıdaki koda bakın:

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

3
nullArgüman olarak verilirse yöntemin bir NPE atmasının makul olduğunu düşünüyorum . Bu, standart kitaplıkta en yaygın davranıştır.
aioobe

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

Her şeyi / iki kez, sonra tekrar eşleştirin. Üçüncüsü senin istediğin

Maçlar geçen / nerede devlet anlatmak için kullanılabilir


Bunun çok güzel bir cevap olduğundan eminim, ama bunu kodumda nasıl kullanırım?
ARK

@ Andcoz'un cevabına bakın (farklı regexp, ancak fikir aynı)
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;
}

3

Bugünlerde Apache Commons Lang's StringUtils desteği var ,

Bu ilkeldir:

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

probleminiz için aşağıdakileri kodlayabilirsiniz: StringUtils.ordinalIndexOf(uri, "/", 3)

LastOrdinalIndexOf yöntemiyle bir dizedeki bir karakterin son n . Oluşumunu da bulabilirsiniz .


3

Belki bunu String.split (..) yöntemi ile de başarabilirsiniz.

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

2

Başka bir yaklaşım:

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

2

Bu cevap @aioobe'nin cevabını geliştirir. Bu cevaptaki iki hata düzeltildi.
1. n = 0 -1 döndürmelidir.
2. n. Oluşum -1 döndürdü, ancak n-1'inci oluşumlarda çalıştı.

Bunu dene !

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

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

1

Çözümüm:

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

0

Kod, alt dizge aka alan genişliği n'inci oluşum konumlarını döndürür. Misal. dize eğer "düşük melow içinde Yığın taşması" arama dizedir 2 belirteç "düşük" bir durum oluşmasına, bunu 2 oluşumu subtring altında olduğunu benimle aynı fikirde olacak "18 ve 21" . indexOfOccurance ("Düşük melow'da yığın taşması", düşük, 2) bir dizede 18 ve 21'i döndürür.

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

2
Bu kod soruyu çözebilirken, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere , gönderinizin kalitesini artırmaya gerçekten yardımcı olur ve muhtemelen daha fazla oy almanıza neden olur. Sadece şu anda soran kişi için değil, gelecekte okuyucular için soruyu yanıtladığınızı unutmayın. Açıklamalar eklemek ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge vermek için lütfen cevabınızı düzenleyin.
Pika Balinaların Büyücüsü

0

// scala

// değer n'inci kez mevcut değilse, n-1'inci zamana kadar mevcut olsa bile -1 atar. // değer n. kez mevcutsa dizini atar

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.