จะหาอักขระที่ n ในสตริงได้อย่างไร?


96

คล้ายกับคำถามที่โพสต์ไว้ที่นี่ฉันกำลังมองหาวิธีแก้ปัญหาใน Java

นั่นคือจะหาดัชนีของการเกิดอักขระ / สตริงที่ n จากสตริงได้อย่างไร?

ตัวอย่าง: " / folder1 / folder2 / folder3 / " ในกรณีนี้ถ้าฉันขอเครื่องหมายทับ (/) ครั้งที่ 3 จะปรากฏก่อนโฟลเดอร์ 3 และฉันคาดว่าจะส่งคืนตำแหน่งดัชนีนี้ ความตั้งใจที่แท้จริงของฉันคือการตั้งค่าจากอักขระที่ n ที่เกิดขึ้น

มีวิธีการใดที่สะดวก / พร้อมใช้งานใน Java API หรือเราต้องเขียนตรรกะเล็ก ๆ ด้วยตัวเองเพื่อแก้ปัญหานี้?

นอกจากนี้

  1. ฉันค้นหาอย่างรวดเร็วว่ารองรับวิธีการใดเพื่อจุดประสงค์นี้ที่StringUtilsของ Apache Commons Lang แต่ฉันไม่พบเลย
  2. นิพจน์ทั่วไปสามารถช่วยในเรื่องนี้ได้หรือไม่?

2
สำหรับตัวอย่างของคุณขึ้นอยู่กับสิ่งที่คุณต้องการทำกับผลลัพธ์การแยกสตริงบน / อาจจะง่ายกว่าซึ่งอาจให้สิ่งที่คุณต้องการโดยตรง?
The Archetypal Paul

@ พอล: นั่นก็เป็นความคิดที่ดีเช่นกัน
Gnanam

คำตอบ:


131

หากโปรเจ็กต์ของคุณขึ้นอยู่กับ Apache Commons อยู่แล้วคุณสามารถใช้ได้StringUtils.ordinalIndexOfมิฉะนั้นนี่คือการนำไปใช้:

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

โพสต์นี้ได้รับการเขียนใหม่เป็นบทความที่นี่


นอกเหนือจากข้อผิดพลาด "off-by-one" แล้วยังมีอีกหนึ่งผลบวกที่ยอดเยี่ยมในการแก้ปัญหาของ @Jon Skeet - ด้วยการปรับเปลี่ยนเล็กน้อย (ย้อนกลับการวนซ้ำ) คุณสามารถมี "เหตุการณ์ที่ n จากครั้งสุดท้าย" ได้เช่นกัน
Karan Chadha

@KaranChadha เช่นเดียวกันกับโซลูชันนี้ เพียงแค่เปลี่ยนเป็นlastIndexOf.
aioobe


28

สองตัวเลือกง่ายๆเกิดขึ้น:

  • ใช้charAt()ซ้ำ ๆ
  • ใช้indexOf()ซ้ำ ๆ

ตัวอย่างเช่น:

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

ซึ่งอาจทำงานได้ไม่ดีเท่าการใช้indexOfซ้ำ ๆ แต่อาจจะง่ายกว่าที่จะทำให้ถูกต้อง


15

คุณสามารถลองสิ่งนี้:

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

โปรดทราบว่าฉันได้ตั้งสมมติฐานบางอย่างใน regex:

  • เส้นทางอินพุตเป็นค่าสัมบูรณ์ (เช่นเริ่มต้นด้วย "/");
  • คุณไม่จำเป็นต้องมี "/" ที่ 3 ในผลลัพธ์

ตามที่ร้องขอในความคิดเห็นฉันจะพยายามอธิบาย regex: (/[^/]*){2}/([^/]*)

การแสดงภาพนิพจน์ทั่วไป

  • /[^/]*เป็น/ตามด้วย[^/]*(จำนวนตัวอักษรที่ไม่ได้ใด ๆ/)
  • (/[^/]*)จัดกลุ่มนิพจน์ก่อนหน้าในเอนทิตีเดียว นี่คือ1กลุ่ม st ของนิพจน์
  • (/[^/]*){2}หมายความว่ากลุ่มจะต้องตรงกับ{2}เวลาที่ไม่แน่นอน
  • [^/]*เป็นอีกครั้งที่จำนวนตัวอักษรที่ไม่ใด ๆ/,
  • ([^/]*)จัดกลุ่มนิพจน์ทั่วไปในเอนทิตีเดียว นี่คือ2กลุ่มที่ n ของนิพจน์

ด้วยวิธีนี้คุณจะได้รับสตริงย่อยที่ตรงกับกลุ่มที่ 2 เท่านั้น: return m.group(2);

เอื้อเฟื้อภาพโดยDebuggex


1
คุณช่วยอธิบาย regex เป็นภาษาอังกฤษธรรมดาได้ไหม ชอบ: แบ็กสแลชตามด้วยอะไรก็ได้ที่ไม่ใช่แบ็กสแลคเป็นจำนวนครั้งไม่ จำกัด ... ถ้าอย่างนั้นฉันก็ไม่แน่ใจ
Ced

1
@Ced ฉันได้เพิ่มคำอธิบายและการแก้ไขเล็กน้อยใน regex ฉันหวังว่าตอนนี้จะชัดเจนขึ้น
andcoz

ขอบคุณที่อธิบาย regex
Vishwa Ratna

8

ฉันทำการเปลี่ยนแปลงเล็กน้อยกับคำตอบของ aioobe และได้รับเวอร์ชัน lastIndexOf ที่ n และแก้ไขปัญหา NPE บางอย่าง ดูรหัสด้านล่าง:

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
ฉันคิดว่ามันสมเหตุสมผลที่เมธอดจะพ่น NPE ถ้าให้nullเป็นอาร์กิวเมนต์ นี่เป็นลักษณะการทำงานที่พบบ่อยที่สุดในไลบรารีมาตรฐาน
aioobe

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

จับคู่สิ่งที่ตามด้วย / สองครั้งแล้วอีกครั้ง อันที่สามคือสิ่งที่คุณต้องการ

Matcherรัฐสามารถใช้ในการบอกที่ / สุดท้ายคือ


ฉันแน่ใจว่านี่เป็นคำตอบที่ยอดเยี่ยมมาก แต่ฉันจะใช้สิ่งนี้ในรหัสของฉันได้อย่างไร
ARK

ดูคำตอบของ @ andcoz (regexp ต่างกัน แต่ความคิดเหมือนกัน)
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

ปัจจุบันมีการสนับสนุนของ Apache คอมมอนส์แลงStringUtils ,

นี่คือดั้งเดิม:

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

สำหรับปัญหาของคุณคุณสามารถเขียนโค้ดต่อไปนี้: StringUtils.ordinalIndexOf(uri, "/", 3)

คุณยังสามารถค้นหาการเกิดครั้งที่ n สุดท้ายของอักขระในสตริงด้วยเมธอดlastOrdinalIndexOf



2

อีกแนวทางหนึ่ง:

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

คำตอบนี้ช่วยปรับปรุงคำตอบของ @aioobe ข้อบกพร่องสองข้อในคำตอบนั้นได้รับการแก้ไขแล้ว
1. n = 0 ควรคืนค่า -1
2. เหตุการณ์ที่ n คืนค่า -1 แต่มันทำงานกับการเกิด n-1

ลองดูสิ!

    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

วิธีแก้ปัญหาของฉัน:

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

โค้ดส่งคืนตำแหน่งย่อยที่ n ตำแหน่งย่อยหรือที่เรียกว่าความกว้างของฟิลด์ ตัวอย่าง. ถ้าสตริง"ล้น Stack ใน melow ต่ำ"เป็นสตริงที่ค้นหา2 occurance ของเข็ม "ต่ำ" คุณจะเห็นด้วยกับผมว่ามัน 2 occurance ที่ subtring "18 และ 21" indexOfOccurance ("Stack overflow in low melow", low, 2) ส่งคืน 18 และ 21 ในสตริง

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
แม้ว่ารหัสนี้จะช่วยแก้ปัญหาได้รวมถึงคำอธิบายว่าทำไมจึงแก้ปัญหานี้ได้จะช่วยปรับปรุงคุณภาพของโพสต์ของคุณได้อย่างแท้จริงและอาจส่งผลให้มีการโหวตเพิ่มขึ้น จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่แค่คนที่ถามตอนนี้ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้
Pika lè Sorcerer of the Whales

0

// สกาลา

// throw's -1 หากไม่มีค่าเป็นครั้งที่ n แม้ว่าจะมีอยู่จนถึงเวลาที่ n-1 ก็ตาม // throw's index หากมีค่าเป็นครั้งที่ n

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.