如何查找字符串中字符的第n个出现?


95

此处发布的问题类似,我正在寻找Java解决方案。

也就是说,如何从字符串中找到第n个出现的字符/字符串的索引?

例如:/ folder1 / folder2 / folder3 / ”。在这种情况下,如果我要求第三次出现斜杠(/),它会出现在folder3之前,并且我希望返回该索引位置。我的实际意图是从字符的第n次出现开始对它进行子串化。

Java API中是否有任何方便/易于使用的方法,还是我们需要自己编写一个小的逻辑来解决这个问题?

也,

  1. 我迅速在Apache Commons Lang的StringUtils中搜索是否为此目的支持任何方法,但没有找到任何方法。
  2. 正则表达式可以在这方面有所帮助吗?

2
对于您的特定示例,根据要对结果执行的操作,可能更容易在/上拆分字符串,这很可能直接为您提供所需的信息?
原型保罗

@Paul:这也是一个好主意。
Gnanam

Answers:


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

这篇文章在这里已被重写为文章。


除了“ by-by-one”错误外,@ Jon Skeet的解决方案还有一个很大的好处-稍作调整(反转循环),您也可以拥有“从最后一次出现的第n次出现”。
卡兰·查达

@KaranChadha,同样适用于此解决方案。只需更改为即可lastIndexOf
aioobe


27

发生两个简单的选择:

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

请注意,我在正则表达式中做了一些假设:

  • 输入路径是绝对的(即以“ /”开头);
  • 您不需要结果中的第三个“ /”。

根据评论的要求,我将尝试解释正则表达式: (/[^/]*){2}/([^/]*)

正则表达式可视化

  • /[^/]*是一个/后跟[^/]*(不是的任意数量的字符/),
  • (/[^/]*)将先前的表达式分组到一个实体中。这是1表达式的第一个组,
  • (/[^/]*){2}表示该组必须完全匹配{2}
  • [^/]*同样是任意数量的非字符/
  • ([^/]*)将previos表达式归为一个实体。这是2表达式的第n组。

这样,您只需要获取与第二个组匹配的子字符串即可: return m.group(2);

图片由Debuggex提供


1
你能用简单的英语解释正则表达式吗?就像:反斜杠后面跟着不是反斜杠的任何东西都无限次...然后我不确定。
2013年

1
@Ced,我为正则表达式添加了一个解释和一个小修正。我希望现在更加清楚。
andcoz 2015年

感谢您解释正则表达式。
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 2015年

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

匹配后跟/两次,然后再次匹配。第三个是你想要的

匹配器的状态可以被用来告诉其中最后一个/是


我确定这是一个很酷的答案,但是如何在代码中使用它呢?
2015年

看看@andcoz的答案(不同的正则表达式,但是想法是一样的)
原型保罗

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的答案上有所改进。该错误的两个错误是固定的。
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个出现位置子字符串(也称为字段宽度)。例。如果字符串“ Stacklowing in low melow”是用于搜索令牌“ low”的第二次出现的字符串,则您将与我同意,第二次出现在子代“ 18和21”处。indexOfOccurance(“低溢出堆栈中的堆栈”,低,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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.