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

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

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

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

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

还有,

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

【问题讨论】:

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

标签: java string substring


【解决方案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;
                              }
                              

                              【讨论】:

                                猜你喜欢
                                • 2011-02-04
                                • 2010-12-25
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2016-11-21
                                • 1970-01-01
                                相关资源
                                最近更新 更多