Вы действительно очень близки к ответу: просто сделайте сопоставление второго символа необязательным.
String s = "1a2b3c4d5";
System.out.println(s.replaceAll(".(.)?", "$1"));
// prints "abcd"
Это работает, потому что:
- Regex по умолчанию жадный, он будетвозьмите второй символ, если он есть
- Когда ввод имеет нечетную длину, второй символ не будет присутствовать при последней замене, но вы все равно будете соответствовать одному символу (то есть последнему символу на входе)
- Вы все еще можете использовать обратные ссылки при замене, даже если группа не соответствует
- Она будет подставлена в пустую строку, а не
"null"
- Thisотличается от
Matcher.group(int)
, который возвращает null
для неудачных групп
Ссылки
Подробное рассмотрение первой части
Давайте подробнее рассмотрим первую часть домашнего задания:
String s = "1a2b3c4d5";
System.out.println(s.replaceAll("(.).", "$1"));
// prints "12345"
Здесь вам не нужно было использовать ?
для второго символа, но он "работает", потому что даже если выне соответствует последнему символу, вам не нужно было! Последний символ может остаться несоответствующим, не замененным из-за проблемной спецификации.
Теперь предположим, что мы хотим удалить символыс индексом 1,3,5 ... и поместите символы с индексом 0,2,4 ... в скобки.
String s = "1a2b3c4d5";
System.out.println(s.replaceAll("(.).", "($1)"));
// prints "(1)(2)(3)(4)5"
А-ха !!Теперь у вас точно такая же проблема с вводом нечетной длины!Вы не могли сопоставить последний символ с вашим регулярным выражением, потому что вашему регулярному выражению нужны два символа, но в конце есть только один символ для ввода нечетной длины!
Решение, опять же, состоит в том, чтобы сопоставить второесимвол необязательно:
String s = "1a2b3c4d5";
System.out.println(s.replaceAll("(.).?", "($1)"));
// prints "(1)(2)(3)(4)(5)"