Как в replaceAll проверить пустая ли группа?

Пишу программу на java. Осуществляю отображение введенных данных по маске. Есть строчка с именем человека. В поле может быть Фамилия или Фамилия Имя Отчество (от 1 до 3 слов).

Маска выводит "Фамилия И." (Первое слово плюс первая буква второго слова плюс точка).

Для вывода использую replaceAll("\\s*(\\S{0,20})\\S*\\s*(\\S)?.*","$1 $2.").

При нынешнем выводе, если в поле одно слово я получаю "Фамилия .". Можно ли как-то если в поле 1 слово, не выводить точку?

Нужно Чтобы

"Фамилия" -> "Фамилия"
"Фамилия Имя" -> "Фамилия И."
"Фамилия Имя Отчество" -> "Фамилия И."

Для реализации думаю нужно исправить второй аргумент функции "$1 $2." так чтобы точка выводилось только если есть второй аргумент. Знаете как это сделать?


Ответы (1 шт):

Автор решения: Wiktor Stribiżew

Для пропуска однословных строк ваше регулярное выражение не должно их находить, используйте

String result = text.replaceFirst("^(\\S+)\\s+(\\S).*", "$1 $2.");

См. пример работы регулярного выражения.

Подробности

  • ^ - начало строки
  • (\S+) - Подмаска №2: один и более непробельных символов
  • \s+ - один и более пробельных символов (\h+ находит только горизонтальные пробелы)
  • (\S) - Подмаска №2: один непробельный символ
  • .* - осатльная часть строки.

Пример работы кода в Java:

List<String> strs = Arrays.asList("Фамилия Имя Отчество", "Фамилия Имя", "Фамилия");
for (String str : strs)
    System.out.println(str.replaceFirst("^(\\S+)\\s+(\\S).*", "$1 $2."));

Результат:

Фамилия И.
Фамилия И.
Фамилия

Если вам нужно оставить регулярное выражение без изменений, а изменить только замену, вам придётся использовать что-то вроде

List<String> strs = Arrays.asList("Фамилия Имя Отчество", "Фамилия Имя", "Фамилия");
Pattern p = Pattern.compile("\\s*(\\S{0,20})\\S*\\s*(\\S)?.*");
for (String str : strs) {
    Matcher m = p.matcher(str);
    System.out.println(m.replaceAll(x -> x.group(1) + (x.group(2) == null ? "" : " " + x.group(2) + ".")) );
}

См. пример работы кода.

→ Ссылка