2015-10-11 13 views
5

Nessuna domanda su SO affronta il mio particolare problema. Conosco molto poco sull'espressione regolare. Sto costruendo un parser di espressioni in Java usando Regex Class per questo scopo. Voglio estrarre operandi, argomenti, operatori, simboli e nomi di funzioni dall'espressione e quindi salvare in ArrayList. Attualmente sto usando questa logicaEspressione regolare per estrarre gli operandi dall'espressione matematica

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); 
} 

uscita:

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

problema è che ora espressione può contenere Matrix con il formato definito dall'utente. Voglio trattare ogni Matrice come un Operando o Argomento in caso di funzioni.

Ingresso 1:

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

uscita dovrebbe essere:

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

Ingresso 2:

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

uscita dovrebbe essere:

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

Ingresso 3:

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

uscita dovrebbe essere:

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

voglio che ormai ArrayList dovrebbe contenere ogni operando, operatori, argomenti, funzioni e simboli ad ogni indice. Come posso ottenere il risultato desiderato utilizzando l'espressione regolare. La convalida dell'espressione non è richiesta.

+2

@trashgod I pensa che il link che hai fornito non sia rilevante per il mio problema. –

risposta

1

penso che si può provare con qualcosa di simile:

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

DEMO

elementi vengono acquisite in gruppi di cattura denominati. Se non ne hai bisogno, è possibile utilizzare breve:

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


La staffa \[[^\]]+\]|<[^>]+>|\{[^\}]+\} partita di apertura ({, [ o <), i caratteri non staffa clasing, e la staffa di chiusura (}, ], >) quindi se non ci sono parentesi dello stesso tipo nidificate, non ci sono problemi. Implementatin in 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"); 
     } 
    } 
} 

Spiegazione di alternative:

  • \[[^\]]+\]|<[^>]+>|\{[^\}]+\} - Partita staffa di data tipo, di carattere che non sono chiudendo la staffa di quel tipo (tutto byt non chiude parentesi di apertura) e parentesi di chiusura di tale tipo ,
  • \d+[eE][-+]\d+ = cifra, seguito da e o E, seguita da operatore + o -, seguita da cifre, per acquisire elementi come 2e+3
  • \w+(?=\() - corrisponde uno o più caratteri alfanumerici (A-Za-z0-9_) se è seguita da ( per funzioni corrispondenti come sin,
  • \w+ - corrisponde a uno o più caratteri di parola (A-Za-z0-9_) per gli operandi
  • [-+\/*%] - corrisponde a un carattere della classe di carattere, per corrispondere a operatori
  • . - corrisponde con nessun altro personaggio, per abbinare altri simboli

Ordine di alternative è molto importante, come ultima alternativa . corrisponderà qualsiasi carattere, quindi ha bisogno di essere ultima opzione. Caso simile con \w+(?=\() e \w+, il secondo corrisponderà a tutto come il precedente, tuttavia se non si desidera distinguere tra funzioni e operandi, lo \w+ sarà sufficiente per tutti.

In più exemple parte (?<name> ...) in ogni alternativa, è un gruppo di cattura di nome, e si può vedere nella demo, come gruppo di frammenti abbinato a gorups come: operando, operatore, la funzione, ecc

+0

Grazie mille. Ha funzionato come un fascino. Come ho detto, sono debole nella comprensione delle regex quindi per favore dimmi cosa sta succedendo qui. –

+0

@KamilMahmood Ho aggiornato la risposta, se non è abbastanza chiara, è stato chiesto a –

+0

Questi numeri 2e-3, 2e + 3, 2E-3 e 2E + 3 non sono trattati correttamente e qual è lo scopo del simbolo XOR "^ ". –

2

Con le espressioni regolari è possibile impostare corrispondente a qualsiasi livello di parentesi bilanciate nidificate.

Ad esempio, nel secondo esempio {[2,5][9/8,func(2+3)]} è necessario abbinare la parentesi graffa di apertura con la parentesi graffa chiusa, ma è necessario tenere traccia di quante ghiere interne di apertura e chiusura/parents/etc ci sono. Questo non può essere fatto con espressioni regolari.

Se, d'altra parte, si semplifica il problema per rimuovere qualsiasi esigenza di bilanciamento, probabilmente è possibile gestirlo con espressioni regolari.

+0

È possibile che io dica la parola "start" da questo e finisca con questo e abbini qualsiasi cosa nel mezzo? –

+0

Non sono sicuro che lo segua. Se vuoi abbinare qualsiasi cosa tra il primo paren di apertura e l'ultimo paren di chiusura puoi fare qualcosa del genere (non testata): '\ ((. *) \)' i parents interiori saranno quello che vuoi. –