2015-12-14 15 views
10

questo è il mio regex:più corrispondenze con delimitatore

([+-]*)(\\d+)\\s*([a-zA-Z]+) 
  • gruppo n ° 1 = firmare
  • gruppo n ° 2 = moltiplicatore
  • gruppo di unità n ° 3 = tempo

Il fatto è che vorrei corrispondere all'input dato ma può essere "incatenato". Quindi il mio input dovrebbe essere valido se e solo se l'intero pattern si ripete senza nulla tra queste occorrenze (eccetto gli spazi bianchi). (Solo una corrispondenza o più corrispondenze una accanto all'altra con possibili spazi bianchi tra di loro).

esempi validi:

1day 
+1day 
-1 day 
+1day-1month 
+1day +1month 
    +1day +1month  

esempi validi:

metodo
###+1day+1month 
+1day###+1month 
+1day+1month### 
###+1day+1month### 
###+1day+1month### 

ho il mio caso posso usare matcher.find(), questo sarebbe fare il trucco, ma accetterà di ingresso in questo modo: +1day###+1month che non è valido per me.

Qualche idea? Questo può essere risolto con più condizioni IF e più controlli per gli indici di inizio e fine, ma sto cercando una soluzione elegante.

EDIT

La regex suggerito nei commenti qui sotto ^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$ sarà parzialmente il trucco, ma se lo uso nel seguente codice si restituisce risultato diverso da quello il risultato che sto cercando. Il problema è che non posso usare (*my regex*)+ perché corrisponderà al tutto.

La soluzione potrebbe essere quella di abbinare il tutto con ingresso ^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$ e quindi utilizzare ([+-]*)(\\d+)\\s*([a-zA-Z]+) con matcher.find() e matcher.group(i) per estrarre ogni partita e dei suoi gruppi. Ma stavo cercando una soluzione più elegante.

risposta

7

Questo dovrebbe funzionare per voi:

^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$ 

In primo luogo, con l'aggiunta all'inizio e alla fine ancore (^ e $), il modello non permetterà caratteri non validi che si verifichi nessuna parte prima o dopo la partita.

Successivamente, ho incluso lo spazio bianco opzionale prima e dopo il motivo ripetuto (\s*).

Infine, l'intero motivo è racchiuso in un ripetitore in modo che possa verificarsi più volte di seguito ((...)+).

Da un lato, si consiglia inoltre di cambiarea [+-]? in modo che possa verificarsi solo una volta.

Online Demo

+0

Thx, per risposta. Hai ragione, ma non l'ho descritto correttamente. Se il mio contributo è valido, devo estrarre per ogni partita il segno, il moltiplicatore e il valore dell'unità temporale. Con la tua soluzione restituirà '+ 1 giorno + 1 mese' come 1 una partita invece di due '+ 1 giorno' e '+ 1 mese' – user1610458

+0

Puoi certamente effettuare il ciclo di tutti i gruppi nella partita. Se ciò non funziona bene per le tue esigenze, potrebbe essere più semplice chiamare semplicemente 'matcher.find' con'^\ s * ([+ -] *) (\ d +) \ s * ([a-zA-Z ] +) 'Più volte, passando ogni volta al successivo indice iniziale. –

0

Si potrebbe utilizzare ^$ per questo, per abbinare l'inizio/fine della stringa

^\s*(?:([+-]?)(\d+)\s*([a-z]+)\s*)+$ 

https://regex101.com/r/lM7dZ9/2

Vedere la Unit Tests per i vostri esempi. Fondamentalmente, devi solo permettere al pattern di ripetere e forzare che nulla oltre lo spazio bianco si verifichi tra le partite.

Combinato con corrispondenza iniziale/fine linea e il gioco è fatto.

0

È possibile utilizzare String.matches o Matcher.matches in Java per adattarsi all'intera regione.

Java Esempio:

public class RegTest { 

    public static final Pattern PATTERN = Pattern.compile(
      "(\\s*([+-]?)(\\d+)\\s*([a-zA-Z]+)\\s*)+"); 

    @Test 
    public void testDays() throws Exception { 
     assertTrue(valid("1 day")); 
     assertTrue(valid("-1 day")); 
     assertTrue(valid("+1day-1month")); 
     assertTrue(valid("+1day -1month")); 
     assertTrue(valid(" +1day +1month ")); 

     assertFalse(valid("+1day###+1month")); 
     assertFalse(valid("")); 
     assertFalse(valid("++1day-1month")); 
    } 

    private static boolean valid(String s) { 
     return PATTERN.matcher(s).matches(); 
    } 
} 
0

È possibile procedere in questo modo:

String p = "\\G\\s*(?:([-+]?)(\\d+)\\s*([a-z]+)|\\z)"; 

Pattern RegexCompile = Pattern.compile(p, Pattern.CASE_INSENSITIVE); 

String s = "+1day 1month"; 

ArrayList<HashMap<String, String>> results = new ArrayList<HashMap<String, String>>(); 

Matcher m = RegexCompile.matcher(s); 
boolean validFormat = false;   

while(m.find()) { 
    if (m.group(1) == null) { 
     // if the capture group 1 (or 2 or 3) is null, it means that the second 
     // branch of the pattern has succeeded (the \z branch) and that the end 
     // of the string has been reached. 
     validFormat = true; 
    } else { 
     // otherwise, this is not the end of the string and the match result is 
     // "temporary" stored in the ArrayList 'results' 
     HashMap<String, String> result = new HashMap<String, String>(); 
     result.put("sign", m.group(1)); 
     result.put("multiplier", m.group(2)); 
     result.put("time_unit", m.group(3)); 
     results.add(result); 
    } 
} 

if (validFormat) { 
    for (HashMap item : results) { 
     System.out.println("sign: " + item.get("sign") 
         + "\nmultiplier: " + item.get("multiplier") 
         + "\ntime_unit: " + item.get("time_unit") + "\n"); 
    } 
} else { 
    results.clear(); 
    System.out.println("Invalid Format"); 
} 

L'ancora \G corrisponde l'inizio della stringa o la posizione dopo la partita precedente. In questo modello, assicura che tutte le partite siano contigue. Se viene raggiunta la fine della stringa, è una prova che la stringa è valida dall'inizio alla fine.

Problemi correlati