2010-10-29 5 views
1

Я знаю, я знаю, теперь у меня есть две проблемы: все это, но регулярное выражение здесь означает, что мне не нужно писать два сложных цикла. Вместо этого у меня есть регулярное выражение, которое я только понимаю, и я буду работать на yonks.Java replaceAll() & split() неровности

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

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

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

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

О, дорогая. Так, я думал, "что бы replaceAll делать в этом случае?":

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

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

[0][1] 

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

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

ответ

4

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

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

Из API documentation:

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

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

строка «бух: и: Foo», например, дает следующие результаты с эти выражения:

Regex  Result 
:  { "boo", "and", "foo" } 
o  { "b", "", ":and:f" } 
+0

Спасибо, это был факт, что split дает мне элемент в массиве для каждого совпадения моего регулярного выражения; это то, чего я не понимал! –

2

Это не прямой ответ на ваш вопрос, однако я хочу показать вам отличный 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); 
} 

Печатается:
0
1

+0

Большое предложение, спасибо. Прямо сейчас я использую только регулярное выражение в этом конкретном экземпляре, но я поеду в Гуаву, если мне это понадобится. –

+0

Google Guava поддерживает регулярное выражение. Как я показал в примере. –

2

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

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

Проблема заключается в том что здесь split.

В рубине, я скажу вам 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 
+0

Интересный подход; благодаря! –