Метод String.replaceAll, обычная магия

интервью Java

Больше отличных статей.

«Микросервисы — это не все, а лишь подмножество определенного домена».

«Подбиблиотека и подтаблица»? Отбор и процесс должны быть осторожными, иначе все выйдет из-под контроля».

С таким количеством компонентов мониторинга всегда найдется подходящий для вас

«С Нетти, что мы разрабатываем? 》

«Вероятно, это наиболее подходящая спецификация Redis».

«Портрет программиста, десять лет взлетов и падений»

Самая полезная серия:

«Наиболее часто используемый набор навыков «vim» в производственной среде Linux.

«Наиболее часто используемый набор навыков «Sed» в производственной среде Linux.

«Наиболее часто используемый набор навыков «AWK» в производственной среде Linux.

Если вы согласны с этими знаниями, приглашаем обратить внимание на вкус Miss Sister в публичном аккаунте WeChat.

ID: xjjdog


Меня обычно не волнует конкретная реализация кода, потому что мой язык разработки очень сложен, и я склонен решать его самым простым и распространенным способом. Сегодня я случайно увидел, как друг в группе отправил следующий код Java, и я чувствую, что я все еще очень ограничен и невежественен:

String str1 = "createTime";
String str2 = "createTimeAt";
String regex = "([A-Z])+";

System.out.println(str1.replaceAll(regex, "_$1").toLowerCase());
System.out.println(str2.replaceAll(regex, "_$1").toLowerCase());

//result
//create_time
//create_time_at

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

"createTime".replaceAll("([A-Z]+)","_$1")

Эта строка кода очень проста, она вызывает метод replaceAll класса String, первым параметром которого является регулярное выражение, а вторым параметром — новое значение, которое нужно заменить.

Что меня поражает, так это то, что в его коде второй параметр replaceAll, который является параметром replace в документации JDK, оказывается_$1. Что это, черт подери, такое? Также поддерживает такие вещи, как заполнители? Я никогда не знал.

исследование проблемы

Поскольку я уже изучал регулярное выражение, наблюдая за первым параметром replaceAll ([AZ]+), я предполагаю, что это должна быть группировка с использованием регулярных выражений, которая соответствует java.util.regex.Matcher в JDK. () метод класса.

В команде Linux Sed просто используйте&Произведены некоторые замены, и причина должна быть той же.

Итак, я посмотрел, как реализован метод String.replaceAll. JDK:

public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

О, оказывается, он использует Matcher внизу, но использует собственный метод replaceAll Matcher. Перейдите к его документации, параметры этого метода действительно призраки, посмотрите на код реализации ниже.

public String replaceAll(String replacement) {
        reset();
        boolean result = find();
        if (result) {
            StringBuilder sb = new StringBuilder();
            do {
                appendReplacement(sb, replacement);
                result = find();
            } while (result);
            appendTail(sb);
            return sb.toString();
        }
        return text.toString();
    }

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

Увидев это, я понимаю, что параметр замены этого метода можно передать через$Символ для обозначения группировки, полученной Matcher путем обычного сопоставления. Он поддерживает два метода имени и числа. Здесь соответствующие методы — группа (имя) и группа (int) класса Matcher.

в заключении

1. Метод replaceAll класса String фактически реализован методом replaceAll() класса java.util.regex.Matcher.
2. Метод replaceAll класса java.util.regex.Matcher реализует логику замены, вызывая метод appendReplacement. 3. Параметр замены метода appendReplacement класса Matcher поддерживает использование символа $ для ссылки на совпадающую группу Matcher.

Следующий код является лучшей практикой для группировки с использованием класса Matcher.

String data = "哈哈哈,xjjdog的手机号码是:12345678901,你会打给我吗";
//通过Matcher的分组功能,可以提取出上面字符串中的手机号
Matcher matcher = Pattern.compile(".*(我的手机号码是:([0-9]{11}))").matcher(data);
while (matcher.find()) {
    System.out.println("G0:" + matcher.group(0));
    System.out.println("G1:" + matcher.group(1));
    System.out.println("G2:" + matcher.group(2));
}
//result
//G0:哈哈哈,xjjdog的手机号码是:12345678901
//G1:xjjdog的手机号码是:12345678901
//G2:12345678901

group(0) означает всю строку
group(1) означает первое совпадение, в приведенном выше примере (мой номер мобильного телефона: ([0-9]{11})) часть
group(2) указывает второе совпадение, которое является частью ([0-9]{11}) в приведенном выше примере.

Использование группировки может быть использовано для извлечения целевого строкового значения в строку, отлично работает!

несколько примеров

Ниже приведены несколько примеров, которые мы можем понять по аналогии.

Горб для подчеркивания именования

public static String camelToUnderline(String camelName) {
return camelName.replaceAll("([A-Z]+)", "_$1").toLowerCase();
}

Подчеркивание в CamelCase

Это чуть более хлопотно и написано имитатором метода Matcher.replaceAll.

public static String underlineToCamel(String underlineName) {
        Matcher matcher = Pattern.compile("(_[a-z]{1})").matcher(underlineName);
        StringBuffer result = new StringBuffer();
        while (matcher.find()) {
            String replacement = matcher.group(1);
            matcher.appendReplacement(result, replacement.replace("_", "").toUpperCase());
        }
        matcher.appendTail(result);
        return result.toString();
}

Кроме того, аналогичный метод (JavaBeansUtil.getCamelCaseString) также предусмотрен в исходном коде плагина Mybatis Generator, вот простая модификация

 public static String getCamelCaseString(String inputString) {
        StringBuilder sb = new StringBuilder();
        boolean nextUpperCase = false;
        for (int i = 0; i < inputString.length(); i++) {
            char c = inputString.charAt(i);
            switch (c) {
                case '_':
                case '-':
                case '@':
                case '$':
                case '#':
                case ' ':
                case '/':
                case '&':
                    if (sb.length() > 0) {
                        nextUpperCase = true;
                    }
                    break;
                default:
                    if (nextUpperCase) {
                        sb.append(Character.toUpperCase(c));
                        nextUpperCase = false;
                    } else {
                        sb.append(Character.toLowerCase(c));
                    }
                    break;
            }
        }
        return sb.toString();
    }

Без комплексного регулярного участия скорость значительно выше.

End

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