#java #regex
Вопрос:
Я пытаюсь создать шаблон регулярного выражения, соответствующий каждому (содержимое*), но шаблон можно найти внутри другого ( (содержимое) (содержимое) ). Я пытался "((.*?))"
, но это возвращает внешние.
Например: строка ('fdmg') (R:Percentual ('dmg') (20))
должна возвращать:
совпадение одно: fdmg
совпадение два: R:Percentual ('dmg') (20)
Редактировать:
Я попробовал это: ((?:[0-9A-Z-a-z "':]|(?R))*)
Но я получаю ошибку рядом с ?R (флаг неизвестности)
Комментарии:
1. Если я правильно помню свои курсы CS, это не может быть правильно сделано с чистыми регулярными выражениями в общем случае, так как для этого потребуется подсчет открывающих и закрывающих скобок. Если есть максимальная глубина вложенности, то для этого вы можете написать уродливое, но работоспособное регулярное выражение. И, возможно, некоторые механизмы регулярных выражений имеют функции, которые позволяют это (что выходит за рамки строгого определения «регулярного выражения»).
Ответ №1:
Я знаю, что это вопрос, связанный с регулярным выражением, но я подумал, что просто добавлю это сюда.
Лично я бы не стал пытаться использовать регулярное выражение для получения определенной вложенной глубины в квадратных скобках, даже если глубина, которую вы пытаетесь получить, составляет всего 1. Ниже приведены несколько методов, которые могут извлекать необходимые заключенные в квадратные скобки подстроки на любой желаемой глубине для типов скобок: ()
, []
, {}
, и <>
:
/**
* This method will parse out (retrieve) the contents of nested brackets
* groups within a bracketed string and return those group contents within a
* Single Dimensional String Array. The best way to see how this works is by
* examples. Let's say we have the following bracketed string:<pre>
*
* String a = "1(2(3)(4))(5(6)(7))";</pre><br>
*
* In the above string we can see that there are two instances of level 1
* bracketed groups which in each level 1 group nest two more level 2
* bracketed groups:
* <pre>
*
* Level 1 Level 2
* (2(3)(4)) (3) (4)
*
* ==================================
*
* Level 1 Level 2
* (5(6)(7)) (6) (7)</pre><br>
*
* Bracketed groups: <b>(2(3)(4))</b> and <b>(5(6)(7))</b> are both
* considered to be at nest level 1 (level 1 is the outer most level). They
* are both individual groups because they both have their own set of outer
* brackets. Within each level 1 group we have two sets of level 2 bracketed
* groups (4 level 2 groups altogether) which consist of: <b>(3)</b> amp;
* <b>(4)</b> and <b>(6)</b> amp; <b>
* (7)</b>.<br><br>
*
* This method also utilizes the bracketsMaxDepth() method.
*
* @param bracketedString (String) The string which contains bracketed
* content to parse.<br>
*
* @param desiredDepth (Integer) Default is 0 (full depth). The
* nested depth to retrieve bracketed content
* from.<br> If the bracket depth supplied is
* deeper than what is contained within the
* supplied input string then an <b>IllegalArgu-
* mentException</b> is thrown explaining as
* such.
*
* @param bracketType (String) You must supply the bracket type to
* process or null to use the default bracket
* type of parentheses ("()"). You can provide
* the bracket type to work against by supplying
* either a single open or close bracket or both
* open and close brackets, for example, any one
* of the following are all acceptable entries if
* parentheses are required:<pre>
*
* "(" ")" "()" ")("</pre><br>
*
* Any one of four (4) bracket types can be supplied. The allowable Bracket
* Types are:<pre>
*
* () Parentheses
* {} Curly Braces
* [] Square Brackets
* amp;<amp;> Chevron Brackets</pre>
*
* @param removeOuterBrackets (Optional - Boolean - Default is false) By
* default the outer brackets for each found
* group are also attached to the returned
* results. If true is supplied to this optional
* parameter then the outer brackets are removed
* from the returned group results.<br>
*
* @return (1D String Array) The determined nested groups desired.<br>
*
* @throws IllegalArgumentException if a depth is supplied greater than the
* available bracketed depth contained
* within the supplied input string. This
* exception is also thrown if it is found
* that the supplied Bracket Type is
* unbalanced (open and closed braces are
* not properly paired) within the supplied
* input string.
*/
public String[] getNestedBracketedGroups(String bracketedString, int desiredDepth,
String bracketType, boolean... removeOuterBrackets) {
boolean removeOuter = false;
if (removeOuterBrackets.length > 0) {
removeOuter = removeOuterBrackets[0];
}
int d = bracketsMaxDepth(bracketedString, bracketType);
if (desiredDepth == 0) {
//Default for this method is 0 (full depth).
desiredDepth = 1;
}
if (d == -1) {
// Throw Exception...
throw new IllegalArgumentException("nngetNestedBracketedGroups() Method Error!n"
"Brackets mismatch in supplied string!n");
}
else if (d < desiredDepth) {
// Throw Another Exception...
throw new IllegalArgumentException("nngetNestedBracketedGroups() Method Error!n"
"Invalid Depth Supplied! Brackets within the supplied string go to an"
"maximum depth of (" d ") and therefore can not go to the supplied "
"depthnof (" desiredDepth "). Change the desired depth.n");
}
char open = '('; // Default
char close = ')'; // Default
String bType = Character.toString(open);
if (bracketType != null amp;amp; !bracketType.trim().isEmpty()) {
bType = Character.toString(bracketType.trim().charAt(0));
}
switch (bType) {
case "(":
case ")":
open = '(';
close = ')';
break;
case "{":
case "}":
open = '{';
close = '}';
break;
case "[":
case "]":
open = '[';
close = ']';
break;
case "<":
case ">":
open = '<';
close = '>';
break;
default:
throw new IllegalArgumentException("ngetNestedBracketedGroups() Method Error!n"
"Unknown bracket type supplied (" bType ")!n");
}
List<String> list = new ArrayList<>();
int n = bracketedString.length();
char[] c = bracketedString.toCharArray();
int depth = 0;
String strg = "";
for (int i = 0; i < n; i ) {
if (c[i] == open) {
depth ;
}
if ((depth >= desiredDepth)) {
if (c[i] == close) {
depth--;
}
strg = Character.toString(c[i]);
if (depth < desiredDepth) {
strg = strg.trim();
if (removeOuter) {
if (strg.startsWith(Character.toString(open))) {
strg = strg.substring(1);
}
if (strg.endsWith(Character.toString(close))) {
strg = strg.substring(0,
strg.lastIndexOf(Character.toString(close)));
}
}
list.add(strg);
strg = "";
}
continue;
}
if (c[i] == close) {
depth--;
}
if (!strg.isEmpty()) {
strg = strg.trim();
if (removeOuter) {
if (strg.startsWith(Character.toString(open))) {
strg = strg.substring(1);
}
if (strg.endsWith(Character.toString(close))) {
strg = strg.substring(0,
strg.lastIndexOf(Character.toString(close)));
}
}
list.add(strg);
strg = "";
}
}
if (!strg.isEmpty()) {
strg = strg.trim();
if (removeOuter) {
if (strg.startsWith(Character.toString(open))) {
strg = strg.substring(1);
}
if (strg.endsWith(Character.toString(close))) {
strg = strg.substring(0,
strg.lastIndexOf(Character.toString(close)));
}
}
list.add(strg);
}
return list.toArray(new String[list.size()]);
}
/**
* This method takes a string and returns the maximum depth of nested
* brackets. The bracket type to check the depth for is supplied within the
* bracketType parameter.<br><br>
*
* @param bracketedString (String) The string to process.<br>
*
* @param bracketType (String - Default is "()") Either a open bracket,
* or a close bracket, or both open and closed
* brackets can be supplied (no white-spaces). This
* method will process any <b>one</b> of 4 different
* bracket types and they are as follows:<pre>
*
* () Parentheses (Default)
* {} Curly Braces
* [] Square Brackets
* amp;<amp;> Chevron Brackets</pre>
*
* @return (Integer) The maximum depth of the supplied bracket type. 0 is
* returned if there are no brackets of the type supplied within the
* supplied string. -1 is returned if there is an unbalance within
* the supplied string of the supplied bracket type. For every open
* bracket there must be a close bracket and visa versa.
*/
public static int bracketsMaxDepth(String bracketedString, String... bracketType) {
char open = '('; // Default
char close = ')'; // Default
if (bracketType.length > 0) {
String bType = Character.toString(bracketType[0].charAt(0));
switch (bType) {
case "(":
case ")":
open = '(';
close = ')';
break;
case "{":
case "}":
open = '{';
close = '}';
break;
case "[":
case "]":
open = '[';
close = ']';
break;
case "<":
case ">":
open = '<';
close = '>';
break;
default:
throw new IllegalArgumentException("nbracketsMaxDepth() Method Error!n"
"Unknown bracket type supplied (" bType ")!n");
}
}
int current_max = 0; // current count
int max = 0; // overall maximum count
int n = bracketedString.length();
char[] c = bracketedString.toCharArray();
// Traverse the input string
for (int i = 0; i < n; i ) {
if (c[i] == open) {
current_max ;
// update max if required
if (current_max > max) {
max = current_max;
}
}
else if (c[i] == close) {
if (current_max > 0) {
current_max--;
}
else {
return -1;
}
}
}
// finally check for unbalanced string
if (current_max != 0) {
return -1;
}
return max;
}
Вот пример того, как вы можете использовать эти методы:
String string = "('fdmg') (R:Percentual ('dmg') (20))";
System.out.println("String with parentheses: " string);
int maxBracketDepth = bracketsMaxDepth(string, "()");
System.out.println("Depth of nested parentheses: " maxBracketDepth);
System.out.println();
System.out.println("WITH BRACKETS:");
System.out.println("==============");
for (int i = 1; i <= maxBracketDepth; i ) {
String[] a = getNestedBracketedGroups(string, i, "()");
System.out.println("Parenthesized groups at depth: " i);
for (String b : a) {
System.out.println(b);
}
System.out.println();
}
System.out.println("WITHOUT BRACKETS:");
System.out.println("=================");
for (int i = 1; i <= maxBracketDepth; i ) {
String[] a = getNestedBracketedGroups(string, i, "()", true);
System.out.println("Parenthesized groups at depth: " i);
for (String b : a) {
System.out.println(b);
}
System.out.println();
}
Окно консоли должно отображаться:
String with parentheses: ('fdmg') (R:Percentual ('dmg') (20))
Depth of nested parentheses: 2
WITH BRACKETS:
==============
Parenthesized groups at depth: 1
('fdmg')
(R:Percentual ('dmg') (20))
Parenthesized groups at depth: 2
('dmg')
(20)
WITHOUT BRACKETS:
=================
Parenthesized groups at depth: 1
'fdmg'
R:Percentual ('dmg') (20)
Parenthesized groups at depth: 2
'dmg'
20
Ответ №2:
Если вы хотите вложить только 2 уровня, как показано в вопросе, но не более глубокую рекурсию, то вы можете сделать это с положительными взглядами.
Регулярное выражение: (?=(([^()]*(?:([^()]*)[^()]*)*)))
Видишь regex101.com для демонстрации.
Результаты (Группа 1*)
('fdmg')
(R:Percentual ('dmg') (20))
('dmg')
(20)
*) Группа 0 всегда является пустой строкой.