Java replaceAll () & split () неровности - PullRequest
1 голос
/ 29 октября 2010

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

У меня есть строка, скажем stack.overflow.questions[0].answer[1].postDate, и мне нужно получить [0] и [1], предпочтительно в массиве. "Легко!" воскликнули мои нейроны, просто используйте regex и метод split в вашей входной строке; поэтому я придумал это:

String[] tokens = input.split("[^\\[\\d\\]]");

, который произвел следующее:

[, , , , , , , , , , , , , , , , [0], , , , , , , [1]]

О, дорогой. Итак, я подумал: «Что будет replaceAll делать в этом случае?»:

String onlyArrayIndexes = input.replaceAll("[^\\[\\d\\]]", "");

который произвел:

[0][1]

Хм. Почему так? Я ищу двухэлементный массив строк, который содержит «[0]» в качестве первого элемента и «[1]» в качестве второго. Почему разделение здесь не работает, когда Javadoc объявляют, что оба используют класс Pattern согласно Javadoc ?

Подводя итог, у меня есть два вопроса: почему вызов split() создает этот большой массив с кажущимися случайными символами пробела и Прав ли я, полагая, что replaceAll работает, потому что регулярное выражение заменяет все символы не совпадают с "[", числом и "]" ? То, что я упускаю, означает, что я ожидаю, что они произведут подобный вывод (хорошо, это три, и, пожалуйста, не отвечайте «подсказка?» На этот!).

Ответы [ 4 ]

4 голосов
/ 29 октября 2010

хорошо из того, что я вижу, split работает, он дает вам массив, который содержит разделенную строку для каждого соответствия, который не является набором скобок с цифрой в середине.

Что касается replaceAll Я думаю, ваше предположение верно. он удаляет все (замените совпадение на ""), что не то, что вы хотите.

Из документации API :

Разбивает эту строку вокруг совпадений данное регулярное выражение.

Этот метод работает, как будто вызывая метод разделения двух аргументов с данное выражение и предельный аргумент нуля. Конечные пустые строки поэтому не включены в результирующий массив.

Строка "boo: and: foo", например, дает следующие результаты с эти выражения:

Regex     Result
:     { "boo", "and", "foo" }
o     { "b", "", ":and:f" }
2 голосов
/ 29 октября 2010

split разделяется на границы , определенные вашим регулярным выражением, поэтому неудивительно, что вы получаете много записей & mdash; почти все символы в строке соответствуют вашему регулярному выражению и, по определению, являются границами, на которых должно произойти разбиение.

replaceAll заменяет совпадения для вашего регулярного выражения заменой, которую вы ему даете, что в вашем случае является пустой строкой.

Если вы пытаетесь захватить 0 и 1, это тривиальный цикл:

String text = "stack.overflow.questions[0].answer[1].postDate";
Pattern pat = Pattern.compile("\\[(\\d+)\\]");
Matcher m = pat.matcher(text);
List<String> results = new ArrayList<String>();
while (m.find()) {
    results.add(m.group(1)); // Or just .group() if you want the [] as well
}
String[] tokens = results.toArray(new String[0]);

Или, если это , всегда ровно два из них:

String text = "stack.overflow.questions[0].answer[1].postDate";
Pattern pat = Pattern.compile(".*\\[(\\d+)\\].*\\[(\\d+)\\].*");
Matcher m = pat.matcher(text);
m.find();
String[] tokens = new String[2];
tokens[0] = m.group(1);
tokens[1] = m.group(2);
2 голосов
/ 29 октября 2010

Это не прямой ответ на ваш вопрос, однако я хочу показать вам отличный API, который удовлетворит ваши потребности.

Извлечение Splitter из Google Guava.

Так что для вашего примера вы можете использовать его так:

Iterable<String> tokens = Splitter.onPattern("[^\\[\\d\\]]").omitEmptyStrings().trimResults().split(input);

//Now you get back an Iterable which you can iterate over. Much better than an Array.
for(String s : tokens) {
   System.out.println(s);
}

Это печатает:01

1 голос
/ 03 июля 2011

Проблема в том, что split здесь неправильная операция.

В ruby ​​я бы сказал вам string.scan(/\[\d+\]/), что даст вам массив ["[0]","[1]"]

Java не имеет эквивалента для одного метода, но мы можем написать метод scan следующим образом:

public List<String> scan(String string, String regex){
   List<String> list = new ArrayList<String>();
   Pattern pattern = Pattern.compile(regex);
   Matcher matcher = pattern.matcher(string);
   while(matcher.find()) {
      list.add(matcher.group());
   }
   return retval;
}

и мы можем назвать его как scan(string,"\\[\\d+\\]")

Эквивалент Scalaкод:

"""\[\d+\]""".r findAllIn string
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...