У меня есть этот код, и я хочу знать, могу ли я заменить только группы (не весь шаблон) в регулярном выражении Java. Код:
//...
Pattern p = Pattern.compile("(\\d).*(\\d)");
String input = "6 example input 4";
Matcher m = p.matcher(input);
if (m.find()) {
//Now I want replace group one ( (\\d) ) with number
//and group two (too (\\d) ) with 1, but I don't know how.
}
java
regex
replace
regex-group
Wokena
источник
источник
Ответы:
Используйте
$n
(где n - цифра) для ссылки на захваченные подпоследовательности вreplaceFirst(...)
. Я предполагаю, что вы хотели заменить первую группу буквальной строкой «число», а вторую группу - значением первой группы.Pattern p = Pattern.compile("(\\d)(.*)(\\d)"); String input = "6 example input 4"; Matcher m = p.matcher(input); if (m.find()) { // replace first number with "number" and second number with the first String output = m.replaceFirst("number $3$1"); // number 46 }
Считайте
(\D+)
для второй группы вместо(.*)
.*
является жадным сопоставителем и сначала будет использовать последнюю цифру. Затем сопоставителю придется вернуться назад, когда он поймет, что в финале(\d)
нет ничего для сопоставления, прежде чем он сможет сопоставить с последней цифрой.источник
m.replaceFirst("number $2$1");
Должно бытьm.replaceFirst("number $3$1");
Вы можете использовать
Matcher#start(group)
иMatcher#end(group)
для создания универсального метода замены:public static String replaceGroup(String regex, String source, int groupToReplace, String replacement) { return replaceGroup(regex, source, groupToReplace, 1, replacement); } public static String replaceGroup(String regex, String source, int groupToReplace, int groupOccurrence, String replacement) { Matcher m = Pattern.compile(regex).matcher(source); for (int i = 0; i < groupOccurrence; i++) if (!m.find()) return source; // pattern not met, may also throw an exception here return new StringBuilder(source).replace(m.start(groupToReplace), m.end(groupToReplace), replacement).toString(); } public static void main(String[] args) { // replace with "%" what was matched by group 1 // input: aaa123ccc // output: %123ccc System.out.println(replaceGroup("([a-z]+)([0-9]+)([a-z]+)", "aaa123ccc", 1, "%")); // replace with "!!!" what was matched the 4th time by the group 2 // input: a1b2c3d4e5 // output: a1b2c3d!!!e5 System.out.println(replaceGroup("([a-z])(\\d)", "a1b2c3d4e5", 2, 4, "!!!")); }
Посмотреть онлайн-демо здесь .
источник
Извините, что побил мертвую лошадь, но это как-то странно, что никто не указал на это: «Да, вы можете, но это противоположно тому, как вы используете группы захвата в реальной жизни».
Если вы используете Regex так, как он предназначен для использования, решение будет таким простым:
"6 example input 4".replaceAll("(?:\\d)(.*)(?:\\d)", "number$11");
Или, как справедливо указал ниже Шмосел,
"6 example input 4".replaceAll("\d(.*)\d", "number$11");
... поскольку в вашем регулярном выражении нет веских причин для группировки десятичных знаков.
Обычно вы не используете группы захвата на тех частях строки, которые хотите отбросить , вы используете их для той части строки, которую хотите сохранить .
Если вам действительно нужны группы, которые вы хотите заменить, то, вероятно, вы захотите использовать механизм шаблонов (например, mustache, ejs, StringTemplate, ...).
Помимо любопытных, даже не захватывающие группы в регулярных выражениях существуют как раз на тот случай, если они нужны механизму регулярных выражений для распознавания и пропуска переменного текста. Например, в
они вам нужны, если ваш ввод может выглядеть как «abcabc capture me bcdbcd» или «abc capture me bcd» или даже просто «захватить меня».
Или, говоря наоборот: если текст всегда один и тот же, и вы его не фиксируете, нет причин использовать группы вообще.
источник
\d(.*)\d
будет достаточно.$11
здесь. Почему 11?Добавьте третью группу, добавив скобки вокруг
.*
, затем замените подпоследовательность на"number" + m.group(2) + "1"
. например:String output = m.replaceFirst("number" + m.group(2) + "1");
источник
"number$21"
работает и"number" + m.group(2) + "1"
не работает.number$21
, заменит группу 21, а не группу 2 + строку «1».Вы можете использовать методы matcher.start () и matcher.end () для получения позиций групп. Таким образом, используя эти позиции, вы легко можете заменить любой текст.
источник
замените поля пароля из ввода:
{"_csrf":["9d90c85f-ac73-4b15-ad08-ebaa3fa4a005"],"originPassword":["uaas"],"newPassword":["uaas"],"confirmPassword":["uaas"]} private static final Pattern PATTERN = Pattern.compile(".*?password.*?\":\\[\"(.*?)\"\\](,\"|}$)", Pattern.CASE_INSENSITIVE); private static String replacePassword(String input, String replacement) { Matcher m = PATTERN.matcher(input); StringBuffer sb = new StringBuffer(); while (m.find()) { Matcher m2 = PATTERN.matcher(m.group(0)); if (m2.find()) { StringBuilder stringBuilder = new StringBuilder(m2.group(0)); String result = stringBuilder.replace(m2.start(1), m2.end(1), replacement).toString(); m.appendReplacement(sb, result); } } m.appendTail(sb); return sb.toString(); } @Test public void test1() { String input = "{\"_csrf\":[\"9d90c85f-ac73-4b15-ad08-ebaa3fa4a005\"],\"originPassword\":[\"123\"],\"newPassword\":[\"456\"],\"confirmPassword\":[\"456\"]}"; String expected = "{\"_csrf\":[\"9d90c85f-ac73-4b15-ad08-ebaa3fa4a005\"],\"originPassword\":[\"**\"],\"newPassword\":[\"**\"],\"confirmPassword\":[\"**\"]}"; Assert.assertEquals(expected, replacePassword(input, "**")); }
источник
Вот другое решение, которое также позволяет заменять одну группу в нескольких матчах. Он использует стеки для изменения порядка выполнения, поэтому строковую операцию можно безопасно выполнять.
private static void demo () { final String sourceString = "hello world!"; final String regex = "(hello) (world)(!)"; final Pattern pattern = Pattern.compile(regex); String result = replaceTextOfMatchGroup(sourceString, pattern, 2, world -> world.toUpperCase()); System.out.println(result); // output: hello WORLD! } public static String replaceTextOfMatchGroup(String sourceString, Pattern pattern, int groupToReplace, Function<String,String> replaceStrategy) { Stack<Integer> startPositions = new Stack<>(); Stack<Integer> endPositions = new Stack<>(); Matcher matcher = pattern.matcher(sourceString); while (matcher.find()) { startPositions.push(matcher.start(groupToReplace)); endPositions.push(matcher.end(groupToReplace)); } StringBuilder sb = new StringBuilder(sourceString); while (! startPositions.isEmpty()) { int start = startPositions.pop(); int end = endPositions.pop(); if (start >= 0 && end >= 0) { sb.replace(start, end, replaceStrategy.apply(sourceString.substring(start, end))); } } return sb.toString(); }
источник