Tutte le risposte fornite in precedenza utilizzano la stessa tecnica (corretta) per utilizzare un lookahead separato per ogni requisito. Ma contengono un paio di inefficienze e un bug potenzialmente enorme, a seconda del back-end che utilizzerà effettivamente la password.
Inizierò con la regex dalla risposta accettata:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Prima di tutto, poiché Java supporta \Ae \zpreferisco utilizzarli per assicurarmi che l'intera stringa sia convalidata, indipendentemente da Pattern.MULTILINE. Ciò non influisce sulle prestazioni, ma evita errori quando le regex vengono riciclate.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
Il controllo che la password non contenga spazi bianchi e il controllo della sua lunghezza minima può essere eseguito in un unico passaggio utilizzando tutto in una volta inserendo quantificatore variabile {8,}sulla scorciatoia \Sche limita i caratteri consentiti:
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
Se la password fornita contiene uno spazio, verranno eseguiti tutti i controlli, solo per far fallire il controllo finale sullo spazio. Questo può essere evitato sostituendo tutti i punti con \S:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
Il punto dovrebbe essere usato solo se vuoi veramente consentire qualsiasi carattere. Altrimenti, usa una classe di caratteri (negata) per limitare la tua regex solo a quei caratteri che sono realmente consentiti. Anche se in questo caso fa poca differenza, non usare il punto quando qualcos'altro è più appropriato è un'ottima abitudine. Vedo troppi casi di backtracking catastrofico perché lo sviluppatore era troppo pigro per usare qualcosa di più appropriato del punto.
Poiché ci sono buone probabilità che i test iniziali trovino un carattere appropriato nella prima metà della password, un quantificatore pigro può essere più efficiente:
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
Ma ora per la questione davvero importante: nessuna delle risposte menziona il fatto che la domanda originale sembra essere stata scritta da qualcuno che pensa in ASCII. Ma in Java le stringhe sono Unicode. I caratteri non ASCII sono consentiti nelle password? Se lo sono, solo gli spazi ASCII non sono consentiti o dovrebbero essere esclusi tutti gli spazi Unicode.
Per impostazione predefinita, \scorrisponde solo agli spazi bianchi ASCII, quindi il suo inverso \Scorrisponde a tutti i caratteri Unicode (spazi bianchi o meno) e a tutti i caratteri ASCII diversi dagli spazi. Se i caratteri Unicode sono consentiti ma gli spazi Unicode non lo sono, UNICODE_CHARACTER_CLASSè possibile specificare il flag per \Sescludere gli spazi Unicode. Se i caratteri Unicode non sono consentiti, è [\x21-\x7E]possibile utilizzarli invece di trovare la \Scorrispondenza con tutti i caratteri ASCII che non sono uno spazio o un carattere di controllo.
Il che ci porta al prossimo potenziale problema: vogliamo consentire ai personaggi di controllo? Il primo passo per scrivere una regex corretta è specificare esattamente cosa vuoi abbinare e cosa no. L'unica risposta tecnicamente corretta al 100% è che la specifica della password nella domanda è ambigua perché non indica se determinati intervalli di caratteri come caratteri di controllo o caratteri non ASCII sono consentiti o meno.