【问题标题】:Java: how to get Iterator<Character> from String [duplicate]Java:如何从字符串中获取 Iterator<Character> [重复]
【发布时间】:2011-04-24 22:02:51
【问题描述】:

我需要来自String 对象的Iterator&lt;Character&gt;。 Java 中是否有任何可用函数可以为我提供此功能,还是我必须自己编写代码?

【问题讨论】:

标签: java string iterator


【解决方案1】:

这感觉很脏,但你可以使用带有空字符串分隔符的 Scanner:

Scanner scanner = new java.util.Scanner(myInput).useDelimiter("");

Scanner 实现了Iterator,因此scanner 现在是长度为1 的字符串的Iterator,这很接近。

要继续(非常?)脏,在 Java 8 中,您可以这样做以简洁地按字符进行迭代:

for (String s: (Iterable<String>)() -> scanner) { 
  char c = s.charAt(0);
  System.out.println(c); 
}

如需详细了解 () -&gt; scanner 为何有效(以及为什么它可能很危险,但在此用例中不适用),请参阅 Explain how this lambda can be assigned to an Iterable

【讨论】:

    【解决方案2】:

    使用 java 8 或更高版本,您可以使用流工具。使用chars() 方法,您可以访问IntStreamIntStream 支持返回 OfInt 迭代器的方法 iterator()OfInt 实现 Iterator&lt;Integer&gt;

    String str = "foobar";
    OfInt ofit = str.chars().iterator();
    Iterator<Integer> it = ofit;
    

    这不是一个完美的答案,因为您要求 Iterator

    顺便说一句:使用 str.codePoints() 您还可以访问代码点 IntStream。

    【讨论】:

    • 你提到了 codePoints()。 codePoints() 的一个重要方面是它允许您处理代理字符。见this answer
    【解决方案3】:
    for (char c : myString.toCharArray()) {
    
    }
    

    【讨论】:

    • 在这样的循环中有效,但 char[] 仍然不能分配给 Iterable&lt;Character&gt;
    • 另外,因为字符串是不可变的,而数组不是,它必须创建一个副本。
    【解决方案4】:

    这可以在 Apache Commons Lang 的帮助下完成(如果您不想使用 Guava,并且想要一个真正的 java.util.Iterator

    private static Iterator<Character> iterator(String string) {
        return Arrays.asList(ArrayUtils.toObject(string.toCharArray())).iterator();
    }
    

    【讨论】:

      【解决方案5】:

      在另一个答案中从其他人那里窃取,这可能是最好的直接实现(如果您不打算使用番石榴)。

      /**
       * @param string
       * @return list of characters in the string
       */
      public static List<Character> characters(final String string) {
      return new AbstractList<Character>() {
              @Override
          public Character get(int index) {
                  return string.charAt(index);
              }
      
              @Override
          public int size() {
                  return string.length();
              }
          };
      }
      

      【讨论】:

        【解决方案6】:

        简答: 不,你必须编码。

        长答案: List 和 Set 都有一个获取Iterator 的方法(还有一些其他的集合类,但可能不是您想要的)。 List 和 Set 接口是 Collections Framework 的一部分,它只允许添加/删除/迭代像 Character 或 Integer 这样的对象(而不是像 char 或 int 这样的基元)。 Java 1.5 called auto-boxing 中有一个功能可以隐藏这个原语到对象的转换,但我不推荐它,在这种情况下它不会提供你想要的。

        另一种方法是将字符串包装在您自己的类中

        implements Iterator<Character>
        

        但这可能比它的价值更多。

        这是一个代码 sn-p 用于做你想做的事情:

        String s = "";
        List<Character> list = new ArrayList<Character>(s.length());
        for (int i = 0; i < s.length(); i++) {
            // note that Character.valueOf() is preferred to new Character()
            // you can omit the Character.valueOf() method
            // and Java 1.5+ will auto-box the primitive into an Object
            list.add(Character.valueOf(s.charAt(i)));
        }
        Iterator<Character> iterator = list.iterator();
        

        【讨论】:

        • ListSet没有实现 Iterator
        • 他们正在实现Iterable 接口(它提供了一个iterator() 函数,它返回一个Iterator)所以没关系。但是您的代码效率低下,因为它创建了字符串的完整副本。
        • @Willi,你是对的,List 和 Set 接口是 Collection 的子接口,其中包含 .interator() 方法。如果您仔细观察,这是通过扩展包含私有子类的抽象类来实现的,这些子类确实实现了 Iterator,它迭代 List 或 Set 中的数据。我应该说 List 和 Set 都提供了获取 Iterator 的方法。
        • @Albert,这个解决方案有点低效,但使用 Iterator 的主要原因之一是因为它允许:“在迭代期间使用明确定义的语义从底层集合中删除元素” ,此解决方案支持。 Guava ImmutableList 返回的 Iterator 实际上是 UnmodifiableIterator guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/…,它在调用 remove() 时会抛出异常。这就引出了一个问题,如果不需要删除,为什么要使用迭代器?
        • @cyber-monk:Iterator 合约明确允许不支持remove()。此外,除了 Iterator 之外,您也别无选择。
        【解决方案7】:

        一种选择是使用Guava

        ImmutableList<Character> chars = Lists.charactersOf(someString);
        UnmodifiableListIterator<Character> iter = chars.listIterator();
        

        这会生成一个由给定字符串支持的不可变字符列表(不涉及复制)。

        但是,如果您最终自己这样做,我建议不要像许多其他示例那样公开Iterator 的实现类。我建议改为创建自己的实用程序类并公开静态工厂方法:

        public static Iterator<Character> stringIterator(final String string) {
          // Ensure the error is found as soon as possible.
          if (string == null)
            throw new NullPointerException();
        
          return new Iterator<Character>() {
            private int index = 0;
        
            public boolean hasNext() {
              return index < string.length();
            }
        
            public Character next() {
              /*
               * Throw NoSuchElementException as defined by the Iterator contract,
               * not IndexOutOfBoundsException.
               */
              if (!hasNext())
                throw new NoSuchElementException();
              return string.charAt(index++);
            }
        
            public void remove() {
              throw new UnsupportedOperationException();
            }
          };
        }
        

        【讨论】:

        • 感谢您的提示。所以我想,我的问题的答案是“否”。
        • @Albert:是的,我认为标准库中没有任何东西可以完全满足您的需求。只是指出可以执行您想要的操作的代码确实存在于一个可靠的、经过良好测试的库中。
        • @Esko:这出现在另一个答案中,我猜它已被删除......他特别需要Iterator&lt;Character&gt;
        • @muffin:Iterator 不是Iterable(并且Character 不是CharSequence)。
        • 但请注意,如果您的字符串具有代理 unicode 字符(即需要表示多个 java 字符的字符),则遍历字符可能不是您想要的。此处的示例代码:gist.github.com/EmmanuelOga/…
        【解决方案8】:

        没有直接的方法。不过,编码并不难:

        public static Iterator<Character> gimmeIterator(final String x) {
                Iterator<Character> it = new Iterator<Character>() {
                    String str = x == null ? "" : x;
                    int pos = -1; // last read
                    public boolean hasNext() {  return(pos+1 <  str.length());  }
                    public Character next() { pos++;  return str.charAt(pos);       }
                    public void remove() {
                        throw new UnsupportedOperationException("remove unsupported for this iterator");
                    }
                };  
                return it;
            }
        

        【讨论】:

          【解决方案9】:

          它不存在,但实现起来很简单:

          class CharacterIterator implements Iterator<Character> {
          
              private final String str;
              private int pos = 0;
          
              public CharacterIterator(String str) {
                  this.str = str;
              }
          
              public boolean hasNext() {
                  return pos < str.length();
              }
          
              public Character next() {
                  return str.charAt(pos++);
              }
          
              public void remove() {
                  throw new UnsupportedOperationException();
              }
          }
          

          实现可能是最有效的。

          【讨论】:

            【解决方案10】:

            Iterator 迭代一个集合或任何实现它的东西。 String 类没有实现这个接口。所以没有直接的办法。

            要遍历一个字符串,你必须首先从它创建一个 char 数组,然后从这个 char 数组创建一个 Collection。

            【讨论】:

            • Iterator 只遍历集合是不正确的。 Iterator 是一个简单的接口,它可以迭代任何它实现的迭代。
            • +1 你有权利,只是失去了我。
            【解决方案11】:

            不确定是否有更直接的方法,但您可以这样做;

            Arrays.asList(string.toCharArray()).iterator();
            

            从头开始; Arrays.asList 并没有像我记得的那样做。

            编辑 2:似乎它在 1.4 中最后一次以这种方式工作

            【讨论】:

            • 但这不是非常低效吗?
            • 是的,这只会创建一个元素Iterator&lt;char[]&gt;
            • 你们俩都是对的。我检查了它并羞愧地哭了。删除评论。我的借口。这不是我最好的一天,真的。
            • 我不相信它在 1.4 中也是如此......我认为在 1.4 中将原始数组传递给 Arrays.asList(Object[]) 是编译器错误。当该方法(错误地)在 1.5 中更改为 varargs 方法时,将原始数组传递给它是合法的,但它并没有达到您的预期。
            【解决方案12】:
            CharacterIterator it = new StringCharacterIterator("abcd"); 
            // Iterate over the characters in the forward direction 
            for (char ch=it.first(); ch != CharacterIterator.DONE; ch=it.next())
            // Iterate over the characters in the backward direction 
            for (char ch=it.last(); ch != CharacterIterator.DONE; ch=it.previous()) 
            

            【讨论】:

            • 这不是Iterator&lt;Character&gt;,我真的只想要这样的东西。
            • @virgium03:同时实现IterableIterator 是一个非常糟糕的主意,不应该这样做。
            • @virgium03:大多是这样。但这是在标准库中吗?
            • @virgium03 您示例中的代码非常损坏。在iterator() 方法中返回this 是完全错误的并且违反了合同。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-11-04
            • 2019-03-16
            • 1970-01-01
            • 1970-01-01
            • 2015-03-04
            • 1970-01-01
            • 2019-02-20
            相关资源
            最近更新 更多