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

Posted

技术标签:

【中文标题】如何在字符串中查找第 n 个出现的字符?【英文标题】:How to find nth occurrence of character in a string? 【发布时间】:2011-04-27 22:59:09 【问题描述】:

类似于here 发布的问题,我正在寻找 在 Java 中的解决方案。

即如何从一个字符串中找到一个字符/字符串第n次出现的索引?

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

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

还有,

    我在 Apache Commons Lang 的StringUtils 上快速搜索是否支持任何方法用于此目的,但没有找到。 正则表达式可以在这方面提供帮助吗?

【问题讨论】:

对于您的特定示例,根据您想要对结果执行的操作,在 / 上拆分字符串可能更容易,这可能会直接为您提供所需的内容? @Paul:这也是个好主意。 【参考方案1】:

如果您的项目已经依赖于 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;


此帖已改写为文章here。

【讨论】:

除了“off-by-one”错误之外,@Jon Skeet 的解决方案还有另一个很大的好处 - 通过小调整(反转循环),您可以从最后一个”。 @KaranChadha,同样适用于这个解决方案。只需更改为lastIndexOf【参考方案2】:

我相信查找第 N 次出现的字符串的最简单解决方案是使用来自 Apache Commons 的 StringUtils.ordinalIndexOf()。

例子:

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

【讨论】:

【参考方案3】:

有两个简单的选择:

反复使用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 好,但它可能更容易正确处理。

【讨论】:

【参考方案4】:

你可以试试这样的:

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/([^/]*)

/[^/]*/ 后跟 [^/]*(任意数量的非 / 字符), (/[^/]*) 将前一个表达式组合在一个实体中。这是表达式的1st 组, (/[^/]*)2 表示该组必须完全匹配 2 次, [^/]* 又是任意数量的不是/ 的字符, ([^/]*) 将 previos 表达式组合在一个实体中。这是表达式的 2nd 组。

这样你只需要得到匹配第二组的子字符串:return m.group(2);

图片由Debuggex提供

【讨论】:

你能用简单的英语解释一下正则表达式吗?喜欢:反斜杠后面跟着任何不是反斜杠的无限时间......然后我不确定。 @Ced,我为正则表达式添加了解释和小修复。我希望现在更清楚了。 感谢您解释正则表达式。【参考方案5】:

我对 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;

【讨论】:

我认为如果给定 null 作为参数,该方法抛出 NPE 是合理的。这是标准库中最常见的行为。【参考方案6】:
 ([.^/]*/)2[^/]*(/)

匹配任何后跟 / 两次,然后再匹配一次。第三个就是你要的那个

Matcher 状态可以用来判断最后一个 / 在哪里

【讨论】:

我确信这是一个非常酷的答案,但是我如何在我的代码中使用它呢? 看@andcoz的回答(正则表达式不同,但思路一样)【参考方案7】:

也许你也可以通过 String.split(..) 方法来实现。

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

【讨论】:

【参考方案8】:
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;

【讨论】:

【参考方案9】:

另一种方法:

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

【讨论】:

【参考方案10】:

现在支持 Apache Commons Lang 的 StringUtils,

这是原语:

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

对于您的问题,您可以编写以下代码:StringUtils.ordinalIndexOf(uri, "/", 3)

您还可以使用 lastOrdinalIndexOf 方法查找字符串中字符的最后第 n 次出现。

【讨论】:

【参考方案11】:

这个答案改进了@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;

【讨论】:

【参考方案12】:

我的解决方案:

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

【讨论】:

【参考方案13】:
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;
        
    

【讨论】:

【参考方案14】:
/* 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;
        
    

【讨论】:

【参考方案15】:

代码返回第 n 个出现位置的子字符串,即字段宽度。例子。如果字符串 "Stack overflow in low melow" 是搜索 2nd 标记“low”出现的字符串,你会同意我的说法,它第二次出现在 subtring “18 和 21”。 indexOfOccurance("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));
    
    

【讨论】:

【参考方案16】:
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;

【讨论】:

虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请编辑您的答案以添加解释并说明适用的限制和假设。【参考方案17】:

//斯卡拉

// 如果该值第 n 次不存在,则抛出 -1,即使它存在直到第 n-1 次。 // 如果该值出现第 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

【讨论】:

【参考方案18】:

APACHE 实现(复制粘贴:不要为一个函数导入整个库!)

这里是与他们的 StringUtils 库分离的确切 Apache Commons 实现(这样您就可以复制粘贴这个并且不必为一个函数添加库的依赖项):

/**
 * <p>Finds the n-th index within a String, handling @code null.
 * This method uses @link String#indexOf(String) if possible.</p>
 * <p>Note that matches may overlap<p>
 *
 * <p>A @code null CharSequence will return @code -1.</p>
 *
 * @param str  the CharSequence to check, may be null
 * @param searchStr  the CharSequence to find, may be null
 * @param ordinal  the n-th @code searchStr to find, overlapping matches are allowed.
 * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
 * @return the n-th index of the search CharSequence,
 *  @code -1 if no match or @code null string input
 */
private static int ordinalIndexOf(final String str, final String searchStr, final int ordinal, final boolean lastIndex) 
    if (str == null || searchStr == null || ordinal <= 0) 
        return -1;
    
    if (searchStr.length() == 0) 
        return lastIndex ? str.length() : 0;
    
    int found = 0;
    // set the initial index beyond the end of the string
    // this is to allow for the initial index decrement/increment
    int index = lastIndex ? str.length() : -1;
    do 
        if (lastIndex) 
            index = str.lastIndexOf(searchStr, index - 1); // step backwards thru string
         else 
            index = str.indexOf(searchStr, index + 1); // step forwards through string
        
        if (index < 0) 
            return index;
        
        found++;
     while (found < ordinal);
    return index;

【讨论】:

【参考方案19】:

看起来你想要子串的字符串是一个文件路径。您不能只按/ 拆分,然后从感兴趣的点开始使用数组条目吗?例如,

String folders = "/folder1/folder2/folder3/".split('/');
StringBuilder subStringed = new StringBuilder('/');
for (int i = 2; i < folders.length; i++) 
  subStringed.append(folders[i]).append('/').;

System.out.println(subStringed.toString());

【讨论】:

【参考方案20】:
static int nthOccurrenceOfChar(String str, int n, char ch) 
    int count = 0;
    for (int i = 0; i < str.length(); i++)
        if (str.charAt(i) == ch && ++count == n)
            return i;
    return -1;

【讨论】:

以上是关于如何在字符串中查找第 n 个出现的字符?的主要内容,如果未能解决你的问题,请参考以下文章

从字符串中查找 C++ 第 n 次出现的子字符串

oracle怎样查找某个字符所在字符串第n次出现的位置

统计字符在字符串中第n次出现的位置

面试题之在字符串中查找出第一个只出现一次的字符的位置

excel 查找某个字符在某行中第N次出现位置

在正则表达式中查找字符串(日期)的倒数第二个出现