文字列でn番目に出現する文字を見つける方法は?


95

ここに投稿された質問と同様に、Javaでの解決策を探しています。

つまり、文字列から文字/文字列のn番目の出現のインデックスを見つける方法は?

例:/ folder1 / folder2 / folder3 /」。この場合、スラッシュ(/)の3番目の出現を要求すると、それはfolder3の前に表示され、このインデックス位置を返すことが期待されます。私の実際の意図は、文字のn番目の出現からそれをサブストリング化することです。

Java APIで利用できる便利ですぐに使えるメソッドはありますか、またはこれを解決するために自分で小さなロジックを記述する必要がありますか?

また、

  1. Apache Commons LangのStringUtilsで、この目的でサポートされているメソッドがあるかどうかをすばやく検索しましたが、見つかりませんでした。
  2. この点で正規表現は役に立ちますか?

2
特定の例では、結果で何をしたいかによって、/で文字列を分割する方が簡単かもしれません。
典型的なポール

@Paul:それもいい考えです。
Gnanam 2010

回答:


128

プロジェクトがすでに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;
}

この投稿は、こちらの記事に書き直されました。


「1つずれた」エラーとは別に、@ Jon Skeetの解決策にはもう1つ大きなメリットがあります-マイナーな調整(ループを逆にする)を使用すると、「最後からn番目の発生」も可能になります。
Karan Chadha 2016年

@KaranChadha、このソリューションにも同じことが当てはまります。に変更してくださいlastIndexOf
aioobe 2016年


27

2つの単純なオプションが発生します。

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

正規表現でいくつかの仮定を行ったことに注意してください:

  • 入力パスは絶対パスです(つまり、「/」で始まります)。
  • 結果の3番目の「/」は必要ありません。

コメントで要求されたように、私は正規表現を説明しようとします: (/[^/]*){2}/([^/]*)

正規表現の視覚化

  • /[^/]*/後に続く[^/]*(a以外の任意の数の文字/)、
  • (/[^/]*)前の式を1つのエンティティにグループ化します。これは式の1stグループです。
  • (/[^/]*){2}グループは完全に一致する必要があることを意味し{2}
  • [^/]*再びない文字の任意の数です/
  • ([^/]*)以前の表現を単一のエンティティにグループ化します。これは式の2 2番目のグループです。

この方法では、2番目のグループに一致する部分文字列を取得するだけで済みます。 return m.group(2);

Debuggexによる画像提供


1
簡単な英語で正規表現を説明できますか?Like:バックスラッシュの後にバックスラッシュではない何かが続く回数は不定です...それではわかりません。
Ced

1
@Ced、私は説明と正規表現に小さな修正を追加しました。私はそれが今より明確であることを望みます。
andcoz

正規表現を説明していただきありがとうございます。
Vishwa Ratna

8

私はaioobeの回答にいくつかの変更を加え、n番目のlastIndexOfバージョンを取得し、いくつかの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
null引数として指定された場合、メソッドがNPEをスローするのは理にかなっていると思います。これは、標準ライブラリで最も一般的な動作です。
aioobe

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

/が後に続くすべてに一致し、次に2回一致します。3番目はあなたが望むものです

マッチャーの最後の/がどこにある状態を伝えるために使用することができます


これは非常に素晴らしい答えだと確信していますが、コードでどのように使用すればよいですか
ARK、

@andcozの回答を見てください(正規表現は異なりますが、考え方は同じです)
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 Commons LangのStringUtilsがサポートされています。

これはプリミティブです:

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

あなたの問題のために、あなたは以下をコーディングすることができます: StringUtils.ordinalIndexOf(uri, "/", 3)

また、lastOrdinalIndexOfメソッドを使用して、文字列内の最後のn番目の文字を見つけることもできます。


3

String.split(..)メソッドを使用してこれを実現することもできます。

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

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の回答を改善します。その答えの2つのバグが修正されました。
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;
        }
    }
}

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

私の解決策:

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

このコードは、n番目の出現位置のサブストリング、つまりフィールド幅を返します。例。文字列「低オーバーフローでのスタックオーバーフロー」が、トークン「低」の2番目の出現を検索するための文字列である場合、2番目の出現はサブトリング「18と21」であることに同意します。indexOfOccurance( "低オーバーフローのスタックオーバーフロー"、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
このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、投票数が増える可能性があります。あなたが今尋ねている人だけでなく、将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
ピカクジラの魔法使い
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.