split()
не является решением этой проблемы, хотя, как продемонстрировал ответ Антти, оно может быть частью решения. Вам будет намного проще сопоставлять числа с нулевым значением в цикле find()
и подсчитывать совпадения следующим образом:
String s = "1.0 5.0 1 5.4 12 0.1 14.2675 0.0 0.00005 0. .0 0000 -0.0";
Pattern p = Pattern.compile("(?<!\\S)-?(?:0+(?:\\.?0*)|\\.0+)(?!\\S)");
Matcher m = p.matcher(s);
int n = 0;
while (m.find()) {
System.out.printf("%n%s ", m.group());
n++;
}
System.out.printf("%n%n%d zeroes total%n", n);
выход:
0.0
0.
.0
0000
-0.0
5 zeroes total
Вот так Тим и хотел, чтобы вы тоже использовали регулярное выражение в своем ответе (я думаю). Разбивая мое регулярное выражение, мы имеем:
(?<!\\S)
- это отрицательный вид сзади, который соответствует позиции, которой не предшествует непробельный символ. Это эквивалентно положительному взгляду Тима, (?<=^|\s)
, который явно соответствует началу строки или сразу после пробела.
-?(?:0+(?:\\.?0*)|\\.0+)
соответствует необязательному знаку минус, за которым следует хотя бы один ноль и не более одного десятичного знака.
(?!\\S)
эквивалентно (?=\s|$)
- оно совпадает непосредственно перед символом пробела или в конце строки.
Взгляд назад и взгляд вперед гарантируют, что вы всегда будете соответствовать целому токену, как если бы вы делились на пустое пространство. Без них он также будет соответствовать нулям, которые являются частью ненулевых токенов, таких как 1230.0456
.
РЕДАКТИРОВАТЬ (в ответ на комментарий): Мое основное возражение против использования split()
заключается в том, что он излишне запутан. Вы создаете массив строк, включающий в себя все части строки, которые вас не интересуют, а затем выполняете некоторые вычисления по длине массива, чтобы получить необходимую информацию. Конечно, это всего лишь одна строка кода, но он очень плохо сообщает о своих намерениях. Любой, кто еще не знаком с этой идиомой, может очень трудно разобраться, что она делает.
Тогда возникает проблема с висячими пустыми токенами: если вы используете технику разделения на моей пересмотренной строке примера, вы получите счетчик 4
, а не 5
. Это связано с тем, что последний фрагмент строки соответствует разделенному регулярному выражению, то есть последний токен должен быть пустой строкой. Но Java (следуя примеру Perl) по умолчанию молча отбрасывает конечные пустые токены. Вы можете переопределить это поведение, передав отрицательное целое число в качестве второго аргумента, но что, если вы забудете это сделать? Это очень простая ошибка, и потенциально очень трудная для устранения.
Что касается производительности, два подхода практически идентичны по скорости (я не знаю, какую память они используют). Это вряд ли будет проблемой при работе с текстами разумного размера.