2015-10-11 5 views
5

Никакой вопрос о SO не касается моей конкретной проблемы. Я мало знаю о регулярном выражении. Я создаю парсер выражений в Java с использованием класса Regex для этой цели. Я хочу извлечь операнды, аргументы, операторы, символы и имена функций из выражения, а затем сохранить в ArrayList. В настоящее время я использую эту логикуРегулярное выражение для извлечения операндов из математического выражения

String string = "2!+atan2(3+9,2+3)-2*PI+3/3-9-12%3*sin(9-9)+(2+6/2)" //This is just for testing purpose later on it will be provided by user 
List<String> res = new ArrayList<>(); 
Pattern pattern = Pattern.compile((\\Q^\\E|\\Q/\\E|\\Q-\\E|\\Q-\\E|\\Q+\\E|\\Q*\\E|\\Q)\\E|\\Q)\\E|\\Q(\\E|\\Q(\\E|\\Q%\\E|\\Q!\\E)) //This string was build in a function where operator names were provided. Its mean that user can add custom operators and custom functions 
Matcher m = pattern.matcher(string); 
int pos = 0; 
while (m.find()) 
{ 
    if (pos != m.start()) 
    { 
     res.add(string.substring(pos, m.start())) 
    } 
    res.add(m.group()) 
    pos = m.end(); 
} 
if (pos != string.length()) 
{ 
    addToTokens(res, string.substring(pos)); 
} 
for(String s : res) 
{ 
    System.out.println(s); 
} 

Выход:

2 
! 
+ 
atan2 
(
3 
+ 
9 
, 
2 
+ 
3 
) 
- 
2 
* 
PI 
+ 
3 
/
3 
- 
9 
- 
12 
% 
3 
* 
sin 
(
9 
- 
9 
) 
+ 
(
2 
+ 
6 
/
2 
) 

Проблема заключается в том, что теперь выражение может содержать матрицу с определенным пользователем форматом. Я хочу рассматривать каждую Матрицу как Операнд или Аргумент в случае функций.

Input 1:

String input_1 = "2+3-9*[{2+3,2,6},{7,2+3,2+3i}]+9*6" 

Выход Должно быть:

2 
+ 
3 
- 
9 
* 
[{2+3,2,6},{7,2+3,2+3i}] 
+ 
9 
* 
6 

Input 2:

String input_2 = "{[2,5][9/8,func(2+3)]}+9*8/5" 

Выход Должно быть:

{[2,5][9/8,func(2+3)]} 
+ 
9 
* 
8 
/
5 

Input 3:

String input_3 = "<[2,9,2.36][2,3,2!]>*<[2,3,9][23+9*8/8,2,3]>" 

Выхода Должен быть:

<[2,9,2.36][2,3,2!]> 
* 
<[2,3,9][23+9*8/8,2,3]> 

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

+2

@trashgod I подумайте, что ссылка, которую вы предоставили, не имеет отношения к моей проблеме. –

ответ

1

Я думаю, вы можете попробовать что-то вроде:

(?<matrix>(?:\[[^\]]+\])|(?:<[^>]+>)|(?:\{[^\}]+\}))|(?<function>\w+(?=\())|(\d+[eE][-+]\d+)|(?<operand>\w+)|(?<operator>[-+\/*%])|(?<symbol>.) 

DEMO

элементы фиксируются в названных групп захвата. Если вам не нужна, вы можете использовать короткие:

\[[^\]]+\]|<[^>]+>|\{[^\}]+\}|\d+[eE][-+]\d+|\w+(?=\()|\w+|[-+\/*%]|. 


\[[^\]]+\]|<[^>]+>|\{[^\}]+\} матч открывающая скобка ({, [ или <), символы не clasing кронштейнах и закрывающая скобка (}, ], >) поэтому, если нет вложенных скобок одного типа, проблем нет. Implementatin в Java:

public class Test { 
    public static void main(String[] args) { 
     String[] expressions = {"2!+atan2(3+9,2+3)-2*PI+3/3-9-12%3*sin(9-9)+(2+6/2)", "2+3-9*[{2+3,2,6},{7,2+3,2+3i}]+9*6", 
     "{[2,5][9/8,func(2+3)]}+9*8/5","<[2,9,2.36][2,3,2!]>*<[2,3,9][23 + 9 * 8/8, 2, 3]>"}; 
     Pattern pattern = Pattern.compile("(?<matrix>(?:\\[[^]]+])|(?:<[^>]+>)|(?:\\{[^}]+}))|(?<function>\\w+(?=\\())|(?<operand>\\w+)|(?<operator>[-+/*%])|(?<symbol>.)"); 
     for(String expression : expressions) { 
      List<String> elements = new ArrayList<String>(); 
      Matcher matcher = pattern.matcher(expression); 
      while (matcher.find()) { 
       elements.add(matcher.group()); 
      } 
      for (String element : elements) { 
       System.out.println(element); 
      } 
      System.out.println("\n\n\n"); 
     } 
    } 
} 

Объяснение альтернатив:

  • \[[^\]]+\]|<[^>]+>|\{[^\}]+\} - матч открытия скобка данного типа, характера, не закрывающей скобкой этого типа (все бют не закрывающая скобка) и закрывающим кронштейном этого типа ,
  • \d+[eE][-+]\d+ = digit, а затем e или E, а затем оператор + или -, следуют цифры, чтобы захватить элементы, такие как 2e+3
  • \w+(?=\() - соответствовать один или несколько символов слова (A-Za-z0-9_) если оно следует ( для согласования таких функций, как sin,
  • \w+ - соответствуют одному или нескольким символам слов (A-Za-z0-9_) для соответствия операндов,
  • [-+\/*%] - соответствует одному символу из класса персонажей, в соответствии с операторами
  • . - совпадает с любым символом, чтобы соответствовать другим символам

Порядок альтернатив весьма важно, так как последняя альтернативой . будет соответствовать любому символу, поэтому он должен быть последним вариантом. Аналогичный случай с \w+(?=\() и \w+, второй будет соответствовать всем, как предыдущий, однако, если вы не хотите различать функции и операнды, то для всех из них будет достаточно \w+.

В более Exemple части (?<name> ...) в каждой альтернативе, является именованным захватом группы, и вы можете увидеть в демо, как группа подогнанных фрагменты в gorups как: операнд, оператор, функция и т.д.

+0

Большое спасибо. Работали как обаяние. Как я уже сказал, я слабо разбираюсь в регулярном выражении, поэтому, пожалуйста, расскажите мне, что здесь происходит. –

+0

@KamilMahmood Я обновил ответ, если он недостаточно ясен, не смог спросить –

+0

Эти цифры 2e-3, 2e + 3, 2E-3 и 2E + 3 обрабатываются неправильно и в чем цель символа XOR "^ ». –

2

С регулярными выражениями вы не можете соответствовать любому уровню вложенных сбалансированных круглых скобок.

Например, в вашем втором примере {[2,5][9/8,func(2+3)]} вам необходимо сопоставить открывающую скобу с закрывающей скобой, но вам нужно отслеживать, сколько открывающих и закрывающих внутренних брекетов/парен/и т.д. есть. Это невозможно сделать с помощью регулярных выражений.

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

+0

Возможно ли, что я говорю, что слово начинается с этого и заканчивается на этом и соответствует чему-либо между ними? –

+0

Не уверен, что я следую. Если вы хотите совместить что-либо между первым начальным паром и последним заключительным париком, вы можете сделать что-то вроде этого (непроверено): '\ ((. *) \)' Внутренние парнеры будут такими, какие вы хотите. –