Java: как получить Iterator <Character> из String

Мне нужен Iterator<Character> от объекта String. Есть ли какая-либо доступная функция в Java, которая предоставляет мне это или мне нужно закодировать свой собственный?

Ответ 1

Один из вариантов заключается в использовании Guava:

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

Это создает неизменный список символов, который поддерживается данной строкой (без копирования).

Если вы в конечном итоге сделаете это сами, я бы рекомендовал не подвергать класс реализации для Iterator, как это делает ряд других примеров. Я бы рекомендовал вместо этого сделать свой собственный класс утилиты и подвергнуть статическому методу factory:

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

Ответ 2

Он не существует, но его тривиально реализовать:

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

Реализация, вероятно, такая же эффективная, как и она.

Ответ 3

for (char c : myString.toCharArray()) {

}

Ответ 4

Кража от кого-то другого в другом ответе, это, вероятно, лучшая прямая реализация (если вы не собираетесь использовать guava).

/**
 * @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();
        }
    };
}

Ответ 5

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

Ответ 6

Короткий ответ: Нет, вам нужно его закодировать.

Длинный ответ: Список и набор имеют метод получения Iterator (есть несколько других классов коллекции, но, вероятно, не то, что вы ищете). Интерфейсы List и Set являются частью Коллекции Framework, которые разрешают добавлять/удалять/итерировать объекты, такие как Character или Integer (не примитивы типа char или int). Существует функция Java 1.5, называемая auto-boxing, которая скроет этот примитив с Object Object, но я не рекомендую его, и он не будет предоставить то, что вы хотите в этом случае.

Альтернативой было бы обернуть String в собственный класс, который

implements Iterator<Character>

но это может быть больше работы, чем это стоит.

Вот фрагмент кода для выполнения того, что вы хотите:

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

Ответ 7

Нет прямого пути. Не сложно скопировать код:

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

Ответ 8

Это можно сделать с небольшой помощью Apache Commons Lang (если вы не хотите использовать Guava и хотите иметь true java.util.Iterator.

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

Ответ 9

Не уверен, есть ли более прямой путь, но вы можете сделать что-то вроде:

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

Забастовкa >

Поцарапайте это; Arrays.asList не делает то, что я, кажется, помню, как он это делает.

Изменить 2: похоже, что последний раз работал таким образом в 1.4

Ответ 10

Iterator перебирать коллекцию или все, что ее реализует. Класс String реализует этот интерфейс. Поэтому нет прямого пути.

Чтобы перебрать строку, вам нужно сначала создать массив char, а затем из этого массива char a Collection.

Ответ 11

С помощью java 8 или new вы можете использовать средство потока. С помощью метода chars() вы можете получить доступ к IntStream. IntStream поддерживает метод iterator(), который возвращает итератор OfInt. OfInt реализует Iterator<Integer>.

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

Это не идеальный ответ, так как вы просили Iterator <Character> .

Btw: С помощью str.codePoints() вы также можете получить доступ к кодовой точке IntStream.

Ответ 12

Это кажется грязным, но вы можете использовать Scanner с пустым разделителем строк:

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

Сканер реализует Iterator, поэтому scanner теперь является Iterator строк длиной-1, который близок.

Чтобы продолжить (очень?) грязный, в Java 8 вы можете сделать это, чтобы лаконично перебирать символы:

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

Подробнее о том, почему работает () -> scanner (и почему это может быть опасно, хотя и не в этом случае), см. Объясните, как эту лямбду можно присвоить Iterable.