Làm thế nào để tìm lần xuất hiện thứ n của ký tự trong một chuỗi?


95

Tương tự như một câu hỏi được đăng ở đây , tôi đang tìm giải pháp trong Java.

Đó là, làm thế nào để tìm chỉ số của lần xuất hiện thứ n của một ký tự / chuỗi từ một chuỗi?

Ví dụ: " / folder1 / folder2 / folder3 / ". Trong trường hợp này, nếu tôi yêu cầu lần xuất hiện thứ 3 của dấu gạch chéo (/), nó xuất hiện trước thư mục3 và tôi mong đợi sẽ trả lại vị trí chỉ mục này. Ý định thực sự của tôi là xâu chuỗi nó từ lần xuất hiện thứ n của một ký tự.

Có phương pháp nào thuận tiện / sẵn sàng sử dụng trong Java API không hay chúng ta cần tự viết một logic nhỏ để giải quyết vấn đề này?

Cũng thế,

  1. Tôi nhanh chóng tìm kiếm xem có phương pháp nào được hỗ trợ cho mục đích này không tại StringUtils của Apache Commons Lang , nhưng tôi không tìm thấy bất kỳ phương pháp nào.
  2. Biểu thức chính quy có thể giúp gì trong vấn đề này không?

2
Đối với ví dụ cụ thể của bạn, tùy thuộc vào những gì bạn muốn làm với kết quả, có thể dễ dàng hơn để chia chuỗi trên /, điều này có thể cung cấp trực tiếp cho bạn những gì bạn cần?
Các nguyên mẫu Paul

@Paul: Đó cũng là một ý kiến ​​hay.
Gnanam

Câu trả lời:


128

Nếu dự án của bạn đã phụ thuộc vào Apache Commons, bạn có thể sử dụng StringUtils.ordinalIndexOf, nếu không, đây là cách triển khai:

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

Bài đăng này đã được viết lại thành một bài báo ở đây .


Ngoài lỗi "từng lỗi một", giải pháp của @Jon Skeet còn có một điểm tích cực khác - Với một chỉnh sửa nhỏ (đảo ngược vòng lặp), bạn cũng có thể có "lần xuất hiện thứ n từ lần cuối cùng".
Karan Chadha

@KaranChadha, giải pháp này cũng áp dụng tương tự. Chỉ cần thay đổi thành lastIndexOf.
aioobe

60

Tôi tin rằng giải pháp dễ nhất để tìm lần xuất hiện thứ N của một Chuỗi là sử dụng StringUtils.ordinalIndexOf () từ Apache Commons.

Thí dụ:

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

27

Hai tùy chọn đơn giản xảy ra:

  • Sử dụng charAt()nhiều lần
  • Sử dụng indexOf()nhiều lần

Ví dụ:

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

Điều đó có thể không hoạt động tốt như sử dụng indexOfnhiều lần, nhưng nó có thể đơn giản hơn để làm đúng.


15

Bạn có thể thử một cái gì đó như sau:

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

Lưu ý rằng tôi đã thực hiện một số giả định trong regex:

  • đường dẫn đầu vào là tuyệt đối (tức là bắt đầu bằng "/");
  • bạn không cần "/" thứ 3 trong kết quả.

Như được yêu cầu trong một nhận xét, tôi sẽ cố gắng giải thích regex: (/[^/]*){2}/([^/]*)

Hình ảnh hóa biểu thức chính quy

  • /[^/]*được /theo sau bởi [^/]*(bất kỳ số ký tự nào không phải là a /),
  • (/[^/]*)nhóm biểu thức trước đó trong một thực thể duy nhất. Đây là 1nhóm thứ nhất của biểu thức,
  • (/[^/]*){2}có nghĩa là nhóm phải khớp với {2}thời gian chính xác,
  • [^/]*lại là bất kỳ số ký tự nào không phải là /,
  • ([^/]*)nhóm biểu thức previos trong một thực thể duy nhất. Đây là 2nhóm thứ hai của biểu thức.

Bằng cách này, bạn chỉ phải lấy chuỗi con phù hợp với nhóm thứ 2: return m.group(2);

Hình ảnh do Debuggex cung cấp


1
bạn có thể giải thích regex bằng tiếng Anh đơn giản không? Giống như: Một dấu gạch chéo ngược theo sau bởi bất kỳ thứ gì không phải là dấu gạch chéo ngược một khoảng thời gian không xác định ... Vậy thì tôi không chắc nữa.
Ced

1
@Ced, tôi đã thêm giải thích và một bản sửa lỗi nhỏ cho regex. Tôi hy vọng nó rõ ràng hơn bây giờ.
andcoz

Cảm ơn vì đã giải thích regex.
Vishwa Ratna

8

Tôi đã thực hiện một vài thay đổi đối với câu trả lời của aioobe và nhận được phiên bản lastIndexOf thứ n và khắc phục một số sự cố NPE. Xem mã bên dưới:

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
Tôi nghĩ rằng phương pháp ném NPE nếu được đưa ra nulldưới dạng đối số là hợp lý. Đây là hành vi phổ biến nhất trong thư viện chuẩn.
aioobe

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

So khớp bất kỳ thứ gì theo sau / hai lần, sau đó lại. Cái thứ ba là cái bạn muốn

Các Matcher nhà nước có thể được sử dụng để cho biết nơi các / cuối cùng là


Tôi chắc chắn đây là một câu trả lời rất thú vị, nhưng làm cách nào để sử dụng điều này trong mã của tôi?
ARK

Nhìn vào @ andcoz của câu trả lời (regexp khác nhau, nhưng ý tưởng là như nhau)
Các nguyên mẫu 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

Ngày nay IS có sự hỗ trợ của Apache Commons Lang's StringUtils ,

Đây là nguyên thủy:

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

đối với vấn đề của bạn, bạn có thể viết mã như sau: StringUtils.ordinalIndexOf(uri, "/", 3)

Bạn cũng có thể tìm lần xuất hiện thứ n cuối cùng của một ký tự trong chuỗi bằng phương thức lastOrdinalIndexOf .


3

Có thể bạn cũng có thể đạt được điều này thông qua phương thức String.split (..).

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

2

Cách tiếp cận khác:

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

Câu trả lời này cải thiện câu trả lời của @aioobe. Hai lỗi trong câu trả lời đó đã được sửa.
1. n = 0 nên trả về -1.
2. Lần xuất hiện thứ n trả về -1, nhưng nó hoạt động với lần xuất hiện thứ n-1.

Thử cái này !

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

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

Giải pháp của tôi:

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

Mã trả về vị trí xuất hiện thứ n chuỗi con còn gọi là chiều rộng trường. Thí dụ. nếu chuỗi "Stack tràn trong low melow" là chuỗi để tìm kiếm lần xuất hiện thứ 2 của mã thông báo "thấp", bạn sẽ đồng ý với tôi rằng lần xuất hiện thứ 2 là khi trừ "18 và 21" . indexOfOccurance ("Tràn ngăn xếp trong melow thấp", thấp, 2) trả về 18 và 21 trong một chuỗi.

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
Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do tại sao điều này giải quyết vấn đề sẽ thực sự giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều phiếu bầu hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những giới hạn và giả định áp dụng.
Pika the Wizard of the Whales,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.