Regex: Voglio questo E questo E quello … in qualsiasi ordine

Non sono nemmeno sicuro che sia ansible o no, ma ecco cosa mi piacerebbe.

String: "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870" 

Ho una casella di testo in cui digito i parametri di ricerca e sono delimitati da spazio. Per questo motivo, voglio restituire una corrispondenza è stringa1 è nella stringa e quindi stringa2 è nella stringa, OR stringa2 è nella stringa e quindi stringa1 è nella stringa. Non m’importa quale sia l’ordine delle corde, ma TUTTI (più o meno a 2) devono essere nella stringa.

Quindi, ad esempio, nella stringa fornita vorrei:

 "FEB Low" 

o

 "Low FEB" 

… per tornare come una partita.

Sono VERAMENTE nuovo di regex, solo leggere alcuni tutorial qui ma è stato qualche tempo fa e ho bisogno di fare questo oggi. Lunedì avvio un nuovo progetto che è molto più importante e non può essere distratto da questo problema. Esiste comunque la possibilità di farlo con espressioni regolari o devo scorrere tutte le parti del filtro di ricerca e permutare l’ordine? Qualsiasi aiuto è estremamente apprezzato. Grazie.

AGGIORNAMENTO: La ragione per cui non voglio scorrere il ciclo e sto cercando le migliori prestazioni è perché, sfortunatamente, il dataTable che sto usando chiama questa funzione su ogni tasto premuto, e non voglio che si impantoli .

AGGIORNAMENTO: Grazie a tutti per il vostro aiuto, è stato molto apprezzato.

AGGIORNAMENTO CODICE:

In definitiva, questo è quello che sono andato con.

 string sSearch = nvc["sSearch"].ToString().Replace(" ", ")(?=.*"); if (sSearch != null && sSearch != "") { Regex r = new Regex("^(?=.*" + sSearch + ").*$", RegexOptions.IgnoreCase); _AdminList = _AdminList.Where( delegate(IPB ipb) { //Concatenated all elements of IPB into a string bool returnValue = r.IsMatch(strTest); //strTest is the concatenated string return returnValue; }).ToList(); } } 

La class IPB ha il numero X di elementi e in nessuna tabella in tutto il sito su cui sto lavorando sono le colonne nello stesso ordine. Pertanto, avevo bisogno di qualsiasi ricerca per ordine e non volevo scrivere molto codice per farlo. C’erano altre buone idee qui, ma so che al mio capo piace molto Regex (le predica) e quindi ho pensato che sarebbe stato meglio se ci fossi andato per ora. Se per qualsiasi motivo il rendimento del sito dovesse scivolare (sito intranet), proverò in un altro modo. Grazie a tutti.

Puoi usare (?=…) lookahead positivo ; asserisce che un dato modello può essere abbinato. Dovresti ancorare all’inizio della stringa, e uno per uno, in qualsiasi ordine, cerca una corrispondenza per ciascuno dei tuoi pattern.

Assomiglierà a qualcosa del genere:

 ^(?=.*one)(?=.*two)(?=.*three).*$ 

Questo corrisponderà a una stringa che contiene "one" , "two" , "three" , in qualsiasi ordine ( come visto su rubular.com ).

A seconda del contesto, potresti voler ancorare su \A e \Z e utilizzare la modalità a riga singola in modo che il punto corrisponda a tutto.

Questa non è la soluzione più efficiente al problema. La soluzione migliore sarebbe quella di analizzare le parole nel tuo input e metterle in una rappresentazione efficiente del set, ecc.

Domande correlate

  • Come funziona l’espressione regolare (?<=#)[^#]+(?=#) ?

Esempio più pratico: convalida della password

Diciamo che vogliamo la nostra password per:

  • Contengono tra 8 e 15 caratteri
  • Deve contenere una lettera maiuscola
  • Deve contenere una lettera minuscola
  • Deve contenere una cifra
  • Deve contenere uno dei simboli speciali

Quindi possiamo scrivere una regex come questa:

 ^(?=.{8,15}$)(?=.*[AZ])(?=.*[az])(?=.*[0-9])(?=.*[[email protected]#$%^&*]).*$ \__________/\_________/\_________/\_________/\______________/ length upper lower digit symbol 

Perché non fare un semplice controllo del testo perché l’ordine non ha importanza?

 string test = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870"; test = test.ToUpper(); bool match = ((test.IndexOf("FEB") >= 0) && (test.IndexOf("LOW") >= 0)); 

Ti serve per usare regex?

Penso che la cosa più vantaggiosa per oggi sia quella di string.Split(' ') i termini di ricerca e quindi sourceString.Contains(searchTerm) i risultati confermando che sourceString.Contains(searchTerm)

 var source = @"NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870".ToLowerInvariant(); var search = "FEB Low"; var terms = search.Split(' '); bool all_match = !terms.Any(term => !(source.Contains(term.ToLowerInvariant()))); 

Si noti che utilizziamo Any() per impostare un cortocircuito, quindi se il primo termine non corrisponde, saltiamo il controllo del secondo, del terzo e così via.


Questo non è un ottimo caso d’uso per RegEx. La manipolazione delle stringhe necessaria per prendere un numero arbitrario di stringhe di ricerca e convertirle in un pattern quasi certamente nega il vantaggio in termini di prestazioni della corrispondenza del modello con il motore RegEx, sebbene questo possa variare a seconda di cosa si sta verificando.

In alcuni commenti hai indicato che vuoi evitare un loop, ma RegEx non è una soluzione one-pass. Non è difficile creare ricerche orribilmente non performanti che eseguono il loop e il passaggio di carattere per carattere, ad esempio il famigerato backtracking catastrofico , in cui una corrispondenza molto semplice richiede migliaia di passaggi per restituire false .

 var text = @"NS306Low FEBRUARY 2FEB0078/9/201013B1-9-1Low31 AUGUST 19870"; var matches = Regex.Matches(text, @"(FEB)|(Low)"); foreach (Match match in matches) { Console.WriteLine(match.Value); } Output: Low FEB FEB Low 

Dovresti iniziare.

La risposta di @polygenelubricants è completa e perfetta, ma avevo un caso in cui volevo abbinare una data e qualcos’altro, ad esempio un numero di 10 cifre in modo che il lookahead non corrisponda e non riesco a farlo con solo lookaheads quindi ho usato i gruppi con nome :

(?:.*(?P<1>[0-9]{10}).*(?P<2>2[0-9]{3}-(?:0?[0-9]|1[0-2])-(?:[0-2]?[0-9]|3[0-1])).*)+

e in questo modo il numero è sempre il gruppo 1 e la data è sempre il gruppo 2. Ovviamente ha alcuni difetti ma è stato molto utile per me e ho pensato di doverlo condividere! (dai uno sguardo https://www.debuggex.com/r/YULCcpn8XtysHfmE )

Non è necessario testare ogni permutazione, basta dividere la ricerca in più parti “FEB” e “Basso” e assicurarsi che ogni parte corrisponda. Sarebbe molto più facile che provare a fare una regex che corrisponda all’intera cosa in un colpo solo (che sono sicuro sia teoricamente ansible, ma probabilmente non pratico nella realtà).

Usa string.Split (). Restituirà un array di sottotitoli che sono delimitati da una stringa / char specificata. Il codice sarà simile a questo.

int maximumSize = 100;
string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string[] individualString = myString.Split(' ', maximumSize);

Per ulteriori informazioni http://msdn.microsoft.com/en-us/library/system.string.split.aspx

Modifica: se si desidera utilizzare le espressioni regolari, questo modello funzionerà. [^ ]* E userete semplicemente Regex.Matches (); Il codice sarà qualcosa del genere:

string myString = "NS306 FEBRUARY 20078/9/201013B1-9-1Low31 AUGUST 19870";
string pattern = "[^ ]*"; Regex rgx = new Regex(pattern);
foreach(Match match in reg.Matches(s))
{
//do stuff with match.value
}