Qual è il miglior metodo di convalida dell'indirizzo e-mail Java? [chiuso]


247

Quali sono le buone librerie di convalida dell'indirizzo e-mail per Java? Esistono alternative al validatore dei beni comuni ?




Non dovresti voler usare librerie (o regex) che non convalidano in modo completo. A causa della complessità dell'indirizzo e-mail valido, non esiste una via di mezzo tra nessuna convalida e convalida completa. L'implementazione di Apache Commons non è completa. Sono a conoscenza di una sola libreria che è ( email-rfc2822-validator ), ma funziona ancora con enormi regex. Un lexer completo è quello che vuoi davvero. EmailValidator4J dice che fa il lavoro, ma non ho esperienza con esso.
Benny Bottema,

1
@BennyBottema Invece di modificare la domanda con un commento, ti preghiamo di fare un post Meta per discutere del motivo per cui questo è stato chiuso se hai ancora domande.
Machavity,

Risposte:


134

Apache Commons è generalmente noto come un progetto solido. Tieni presente, tuttavia, dovrai comunque inviare un'e-mail di verifica all'indirizzo se vuoi assicurarti che sia una vera e-mail e che il proprietario la desideri utilizzata sul tuo sito.

EDIT : c'era un bug in cui era troppo restrittivo sul dominio, causando che non accettava email valide da nuovi TLD.

Questo errore è stato risolto il 03 / Jan / 15 02:48 nella versione 1.4.1 del validatore comune


1
Sono d'accordo con le parti extra che hai citato, ma fanno parte del progetto Commons Validation?
Duffymo,

2
No, la EmailValidatorclasse Apache non invia un messaggio e-mail per la verifica.
Matthew Flaschen,

3
Se il tuo caso d'uso è convalidare l'indirizzo e-mail remoto di un utente, questa soluzione presenta un notevole difetto (simile a InternetAddress.validate ()): EmailValidator considera l'utente @ [10.9.8.7] come indirizzi e-mail validi - che sono secondo RFC, ma forse non per la registrazione utente / modulo di contatto.
zillion1,

1
@zillion, documentato in Apache COmmons: "Questa implementazione non è garantita per rilevare tutti i possibili errori in un indirizzo e-mail." E ho detto cosa devi fare per "assicurarti che sia una vera e-mail". Tuttavia, gli indirizzi con IP locali potrebbero essere validi in ambienti rari.
Matthew Flaschen,

5
EmailValidator di Apache Commons ha un grave svantaggio: non supporta IDN.
Piohen,

261

L'uso del pacchetto di posta elettronica ufficiale java è il più semplice:

public static boolean isValidEmailAddress(String email) {
   boolean result = true;
   try {
      InternetAddress emailAddr = new InternetAddress(email);
      emailAddr.validate();
   } catch (AddressException ex) {
      result = false;
   }
   return result;
}

59
Si noti che InternetAddress.validate () considera l'utente @ [10.9.8.7] e l'utente @ localhost come indirizzi e-mail validi, che sono in base alla RFC. Tuttavia, a seconda del caso d'uso (modulo Web), potresti volerli considerare non validi.
zillion1

8
non solo ciò è valido come ha detto @ zillion1, ma anche cose come bla @ bla sono considerate valide. Davvero non è la soluzione migliore.
Diego Plentz,

4
@NicholasTolleyCottrell Questo è Java, qui lanciamo e catturiamo eccezioni, non capisco davvero il tuo punto
gyorgyabraham

17
Sospetto che il costruttore di InternetAddress sia stato manomesso. Oppure il mio sistema è stato manomesso. Oppure RFC822 è stato manomesso. O potrei davvero usare un po 'di sonno in questo momento. Ma ho appena provato un po 'di codice e le seguenti cinque stringhe passano tutte come indirizzi di posta elettronica validi se le passi al costruttore di InternetAddress e, "chiaramente", non sono valide. Ecco come fare: ., .com, com., abce 123. Inoltre, l'aggiunta di spazi bianchi iniziali o finali non invalida le stringhe. Sii il giudice!
Martin Andersson,

4
um, il formaggio fallisce correttamente quando lo eseguo. a cosa diavolo stai collegando la libreria javax.mail ???
Aaron Davidson,

91

Il validatore di Apache Commons può essere usato come indicato nelle altre risposte.

pom.xml:

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.4.1</version>
</dependency>

build.gradle:

compile 'commons-validator:commons-validator:1.4.1'

L'importazione:

import org.apache.commons.validator.routines.EmailValidator;

Il codice:

String email = "myName@example.com";
boolean valid = EmailValidator.getInstance().isValid(email);

e per consentire gli indirizzi locali

boolean allowLocal = true;
boolean valid = EmailValidator.getInstance(allowLocal).isValid(email);

2
In Android Studio puoi aggiungere la compilazione 'commons-validator: commons-validator: 1.4.1' nella tua app \ build.gradle dipendenze {}
Benjiko99,

2
Dopo aver effettivamente provato a costruire il mio progetto, sembra che Apache Commons non funzioni molto bene con Android, centinaia di avvisi e alcuni errori, non si è nemmeno compilato. Questo è quello che ho finito per usare howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99

1
Lo stesso problema con me di Benjiko99. Dopo aver aggiunto la dipendenza, il progetto non verrà compilato, dice java.exe terminato con un codice di uscita diverso da zero 2.
Amit Mittal

1
Stavo riscontrando errori anche in Android Studio. Ho cambiato da 1.4.1 a 1.5.1 e funziona!
Matt

1
Nota: Use_the Emailvalidator in org.apache.commons.validator.routines poiché EmailValidator in org.apache.commons.validator è deprecato (sto usando 1.6 commons Validator)
HopeKing

71

Risposta in ritardo, ma penso che sia semplice e degno:

    public boolean isValidEmailAddress(String email) {
           String ePattern = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$";
           java.util.regex.Pattern p = java.util.regex.Pattern.compile(ePattern);
           java.util.regex.Matcher m = p.matcher(email);
           return m.matches();
    }

Casi di prova :

inserisci qui la descrizione dell'immagine

Ai fini della produzione, le convalide dei nomi di dominio devono essere eseguite in termini di rete.


40
È un validatore piuttosto brutalmente semplicistico che ignora la maggior parte delle regole RFC insieme agli IDN. Eviterei questo per qualsiasi app di qualità di produzione.
mlaccetti

1
me@azienda.com non sarà valido ...
Alexander Burakevych,

14
Non creare il tuo validatore basato su regex per cose coperte da RFC.
Josh Glover,

6
reinventare la ruota è OK fintanto che non ti dispiace la occasionale gomma a terra
dldnh

è buono ma non per tutti i casi.
Andrain,

21

Se stai cercando di eseguire una convalida del modulo ricevuta dal client o solo una convalida del bean, mantienila semplice. È meglio fare una convalida via e-mail piuttosto che fare una rigida e rifiutare alcune persone (ad esempio quando stanno cercando di registrarsi per il tuo servizio web). Con quasi tutto ciò che è consentito nella parte del nome utente dell'email e così tanti nuovi domini aggiunti letteralmente ogni mese (ad esempio .azienda, .enterprise, .estate), è più sicuro non essere restrittivo:

Pattern pattern = Pattern.compile("^.+@.+\\..+$");
Matcher matcher = pattern.matcher(email);

3
questo è davvero un buon punto, ogni app ragionevole dovrebbe avere altre misure per impedire che questo input venga sfruttato in ogni caso
jmaculate

4
Che ne dici di cambiarlo in "^. + @. + (\\. [^ \\.] +) + $" Per evitare un punto finale?
Xingang Huang,

7

In ritardo alla domanda, qui, ma: mantengo un corso a questo indirizzo: http://lacinato.com/cm/software/emailrelated/emailaddress

Si basa sulla classe di Les Hazlewood, ma presenta numerosi miglioramenti e correzioni di alcuni bug. Licenza Apache.

Credo che sia il parser di posta elettronica più capace in Java, e devo ancora vederne uno più capace in qualsiasi lingua, anche se ce ne potrebbe essere uno là fuori. Non è un parser in stile lexer, ma utilizza alcuni complicati java regex e quindi non è così efficiente come potrebbe essere, ma la mia azienda ha analizzato ben oltre 10 miliardi di indirizzi del mondo reale con esso: è certamente utilizzabile in un rendimento elevato situazione. Forse una volta all'anno colpirà un indirizzo che provoca un overflow dello stack regex (in modo appropriato), ma questi sono indirizzi spam lunghi centinaia o migliaia di caratteri con molte citazioni, parentesi e simili.

RFC 2822 e le relative specifiche sono davvero abbastanza permissive in termini di indirizzi e-mail, quindi una classe come questa è eccessiva per la maggior parte degli usi. Ad esempio, il seguente è un indirizzo legittimo, in base a specifiche, spazi e tutto:

"<bob \" (here) " < (hi there) "bob(the man)smith" (hi) @ (there) example.com (hello) > (again)

Nessun server di posta lo consentirebbe, ma questa classe può analizzarlo (e riscriverlo in un modulo utilizzabile).

Abbiamo trovato che le opzioni esistenti del parser di posta elettronica Java non erano sufficientemente durevoli (il che significa che non potevano analizzare alcuni indirizzi validi), quindi abbiamo creato questa classe.

Il codice è ben documentato e ha molte opzioni facili da modificare per consentire o impedire determinati moduli e-mail. Fornisce inoltre molti metodi per accedere a determinate parti dell'indirizzo (lato sinistro, lato destro, nomi personali, commenti, ecc.), Per analizzare / convalidare le intestazioni dell'elenco delle cassette postali, per analizzare / convalidare il percorso di ritorno (che è unico tra le intestazioni) e così via.

Il codice come scritto ha una dipendenza javamail, ma è facile da rimuovere se non si desidera la funzionalità minore che fornisce.


1
Ciao, l'ho copiato in GitHub per rendere pubblica la comunità open source. Ora tutti possono commentare, documentare e migliorare il codice. github.com/bbottema/email-rfc2822-validator . Usavo
Benny Bottema,

7

Mi chiedo solo perché nessuno sia uscito @Emaildai vincoli aggiuntivi di Hibernate Validator. Lo stesso validatore è EmailValidator.


Sebbene sia un'alternativa ai beni comuni di Apache, la sua implementazione è rudimentale come la maggior parte delle librerie basate su regex. Dai documenti: "Tuttavia, come discusso in questo articolo, non è necessariamente pratico implementare un validatore di e-mail conforme al 100%". L'unico validatore completo basato su regex che conosco è e-mail-rfc2822-validator e altrimenti EmailValidator4J sembra promettente.
Benny Bottema,

5

Les Hazlewood ha scritto una classe di validazione e-mail conforme RFC 2822 molto accurata usando espressioni regolari Java. Puoi trovarlo su http://www.leshazlewood.com/?p=23 . Tuttavia, la sua completezza (o l'implementazione di Java RE) porta all'inefficienza: leggi i commenti sui tempi di analisi per indirizzi lunghi.


1
Ho costruito sulla classe eccellente di Les Hazlewood (che ha alcuni bug). (Vedi la mia risposta separata a questa domanda.) Sebbene abbia mantenuto il metodo java regex, lo utilizziamo perfettamente in un ambiente critico per le prestazioni. Se tutto ciò che stai facendo è analizzare gli indirizzi, le prestazioni potrebbero essere un problema, ma per la maggior parte degli utenti sospetto che sia solo l'inizio di qualunque cosa stiano facendo. I miei aggiornamenti alla classe hanno anche risolto una serie di problemi di lunga ricorsione.
Lacinato,

Questa è una libreria obsoleta ed è stata sostituita due volte, infine da e-mail-rfc2822-validator . Anche se soddisfa ancora tutte le esigenze moderne, è anche soggetto a bug nascosti sulle prestazioni (e non supporta le modifiche limitate dalle più recenti specifiche RFC).
Benny Bottema,

3

Ho trasferito parte del codice in Zend_Validator_Email:

@FacesValidator("emailValidator")
public class EmailAddressValidator implements Validator {

    private String localPart;
    private String hostName;
    private boolean domain = true;

    Locale locale;
    ResourceBundle bundle;

    private List<FacesMessage> messages = new ArrayList<FacesMessage>();

    private HostnameValidator hostnameValidator;

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        setOptions(component);
        String email    = (String) value;
        boolean result  = true;
        Pattern pattern = Pattern.compile("^(.+)@([^@]+[^.])$");
        Matcher matcher = pattern.matcher(email);

        locale = context.getViewRoot().getLocale();
        bundle = ResourceBundle.getBundle("com.myapp.resources.validationMessages", locale);

        boolean length = true;
        boolean local  = true;

        if (matcher.find()) {
            localPart   = matcher.group(1);
            hostName    = matcher.group(2);

            if (localPart.length() > 64 || hostName.length() > 255) {
                length          = false;
                addMessage("enterValidEmail", "email.AddressLengthExceeded");
            } 

            if (domain == true) {
                hostnameValidator = new HostnameValidator();
                hostnameValidator.validate(context, component, hostName);
            }

            local = validateLocalPart();

            if (local && length) {
                result = true;
            } else {
                result = false;
            }

        } else {
            result          = false;
            addMessage("enterValidEmail", "invalidEmailAddress");
        }

        if (result == false) {
            throw new ValidatorException(messages);
        }

    }

    private boolean validateLocalPart() {
        // First try to match the local part on the common dot-atom format
        boolean result = false;

        // Dot-atom characters are: 1*atext *("." 1*atext)
        // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*",
        //        "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~"
        String atext = "a-zA-Z0-9\\u0021\\u0023\\u0024\\u0025\\u0026\\u0027\\u002a"
                + "\\u002b\\u002d\\u002f\\u003d\\u003f\\u005e\\u005f\\u0060\\u007b"
                + "\\u007c\\u007d\\u007e";
        Pattern regex = Pattern.compile("^["+atext+"]+(\\u002e+["+atext+"]+)*$");
        Matcher matcher = regex.matcher(localPart);
        if (matcher.find()) {
            result = true;
        } else {
            // Try quoted string format

            // Quoted-string characters are: DQUOTE *([FWS] qtext/quoted-pair) [FWS] DQUOTE
            // qtext: Non white space controls, and the rest of the US-ASCII characters not
            //   including "\" or the quote character
            String noWsCtl = "\\u0001-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f";
            String qText = noWsCtl + "\\u0021\\u0023-\\u005b\\u005d-\\u007e";
            String ws = "\\u0020\\u0009";

            regex = Pattern.compile("^\\u0022(["+ws+qText+"])*["+ws+"]?\\u0022$");
            matcher = regex.matcher(localPart);
            if (matcher.find()) {
                result = true;
            } else {
                addMessage("enterValidEmail", "email.AddressDotAtom");
                addMessage("enterValidEmail", "email.AddressQuotedString");
                addMessage("enterValidEmail", "email.AddressInvalidLocalPart");
            }
        }

        return result;
    }

    private void addMessage(String detail, String summary) {
        String detailMsg = bundle.getString(detail);
        String summaryMsg = bundle.getString(summary);
        messages.add(new FacesMessage(FacesMessage.SEVERITY_ERROR, summaryMsg, detailMsg));
    }

    private void setOptions(UIComponent component) {
        Boolean domainOption = Boolean.valueOf((String) component.getAttributes().get("domain"));
        //domain = (domainOption == null) ? true : domainOption.booleanValue();
    }
}

Con un validatore del nome host come segue:

@FacesValidator("hostNameValidator")
public class HostnameValidator implements Validator {

    private Locale locale;
    private ResourceBundle bundle;
    private List<FacesMessage> messages;
    private boolean checkTld = true;
    private boolean allowLocal = false;
    private boolean allowDNS = true;
    private String tld;
    private String[] validTlds = {"ac", "ad", "ae", "aero", "af", "ag", "ai",
        "al", "am", "an", "ao", "aq", "ar", "arpa", "as", "asia", "at", "au",
        "aw", "ax", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "biz",
        "bj", "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by", "bz", "ca",
        "cat", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co",
        "com", "coop", "cr", "cu", "cv", "cx", "cy", "cz", "de", "dj", "dk",
        "dm", "do", "dz", "ec", "edu", "ee", "eg", "er", "es", "et", "eu", "fi",
        "fj", "fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh",
        "gi", "gl", "gm", "gn", "gov", "gp", "gq", "gr", "gs", "gt", "gu", "gw",
        "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in",
        "info", "int", "io", "iq", "ir", "is", "it", "je", "jm", "jo", "jobs",
        "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz",
        "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma",
        "mc", "md", "me", "mg", "mh", "mil", "mk", "ml", "mm", "mn", "mo",
        "mobi", "mp", "mq", "mr", "ms", "mt", "mu", "museum", "mv", "mw", "mx",
        "my", "mz", "na", "name", "nc", "ne", "net", "nf", "ng", "ni", "nl",
        "no", "np", "nr", "nu", "nz", "om", "org", "pa", "pe", "pf", "pg", "ph",
        "pk", "pl", "pm", "pn", "pr", "pro", "ps", "pt", "pw", "py", "qa", "re",
        "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si",
        "sj", "sk", "sl", "sm", "sn", "so", "sr", "st", "su", "sv", "sy", "sz",
        "tc", "td", "tel", "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to",
        "tp", "tr", "travel", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "um",
        "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws",
        "ye", "yt", "yu", "za", "zm", "zw"};
    private Map<String, Map<Integer, Integer>> idnLength;

    private void init() {
        Map<Integer, Integer> biz = new HashMap<Integer, Integer>();
        biz.put(5, 17);
        biz.put(11, 15);
        biz.put(12, 20);

        Map<Integer, Integer> cn = new HashMap<Integer, Integer>();
        cn.put(1, 20);

        Map<Integer, Integer> com = new HashMap<Integer, Integer>();
        com.put(3, 17);
        com.put(5, 20);

        Map<Integer, Integer> hk = new HashMap<Integer, Integer>();
        hk.put(1, 15);

        Map<Integer, Integer> info = new HashMap<Integer, Integer>();
        info.put(4, 17);

        Map<Integer, Integer> kr = new HashMap<Integer, Integer>();
        kr.put(1, 17);

        Map<Integer, Integer> net = new HashMap<Integer, Integer>();
        net.put(3, 17);
        net.put(5, 20);

        Map<Integer, Integer> org = new HashMap<Integer, Integer>();
        org.put(6, 17);

        Map<Integer, Integer> tw = new HashMap<Integer, Integer>();
        tw.put(1, 20);

        Map<Integer, Integer> idn1 = new HashMap<Integer, Integer>();
        idn1.put(1, 20);

        Map<Integer, Integer> idn2 = new HashMap<Integer, Integer>();
        idn2.put(1, 20);

        Map<Integer, Integer> idn3 = new HashMap<Integer, Integer>();
        idn3.put(1, 20);

        Map<Integer, Integer> idn4 = new HashMap<Integer, Integer>();
        idn4.put(1, 20);

        idnLength = new HashMap<String, Map<Integer, Integer>>();

        idnLength.put("BIZ", biz);
        idnLength.put("CN", cn);
        idnLength.put("COM", com);
        idnLength.put("HK", hk);
        idnLength.put("INFO", info);
        idnLength.put("KR", kr);
        idnLength.put("NET", net);
        idnLength.put("ORG", org);
        idnLength.put("TW", tw);
        idnLength.put("ایران", idn1);
        idnLength.put("中国", idn2);
        idnLength.put("公司", idn3);
        idnLength.put("网络", idn4);

        messages = new ArrayList<FacesMessage>();
    }

    public HostnameValidator() {
        init();
    }

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        String hostName = (String) value;

        locale = context.getViewRoot().getLocale();
        bundle = ResourceBundle.getBundle("com.myapp.resources.validationMessages", locale);

        Pattern ipPattern = Pattern.compile("^[0-9a-f:\\.]*$", Pattern.CASE_INSENSITIVE);
        Matcher ipMatcher = ipPattern.matcher(hostName);
        if (ipMatcher.find()) {
            addMessage("hostname.IpAddressNotAllowed");
            throw new ValidatorException(messages);
        }

        boolean result = false;

        // removes last dot (.) from hostname 
        hostName = hostName.replaceAll("(\\.)+$", "");
        String[] domainParts = hostName.split("\\.");

        boolean status = false;

        // Check input against DNS hostname schema
        if ((domainParts.length > 1) && (hostName.length() > 4) && (hostName.length() < 255)) {
            status = false;

            dowhile:
            do {
                // First check TLD
                int lastIndex = domainParts.length - 1;
                String domainEnding = domainParts[lastIndex];
                Pattern tldRegex = Pattern.compile("([^.]{2,10})", Pattern.CASE_INSENSITIVE);
                Matcher tldMatcher = tldRegex.matcher(domainEnding);
                if (tldMatcher.find() || domainEnding.equals("ایران")
                        || domainEnding.equals("中国")
                        || domainEnding.equals("公司")
                        || domainEnding.equals("网络")) {



                    // Hostname characters are: *(label dot)(label dot label); max 254 chars
                    // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
                    // id-prefix: alpha / digit
                    // ldh: alpha / digit / dash

                    // Match TLD against known list
                    tld = (String) tldMatcher.group(1).toLowerCase().trim();
                    if (checkTld == true) {
                        boolean foundTld = false;
                        for (int i = 0; i < validTlds.length; i++) {
                            if (tld.equals(validTlds[i])) {
                                foundTld = true;
                            }
                        }

                        if (foundTld == false) {
                            status = false;
                            addMessage("hostname.UnknownTld");
                            break dowhile;
                        }
                    }

                    /**
                     * Match against IDN hostnames
                     * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
                     */
                    List<String> regexChars = getIdnRegexChars();

                    // Check each hostname part
                    int check = 0;
                    for (String domainPart : domainParts) {
                        // Decode Punycode domainnames to IDN
                        if (domainPart.indexOf("xn--") == 0) {
                            domainPart = decodePunycode(domainPart.substring(4));
                        }

                        // Check dash (-) does not start, end or appear in 3rd and 4th positions
                        if (domainPart.indexOf("-") == 0
                                || (domainPart.length() > 2 && domainPart.indexOf("-", 2) == 2 && domainPart.indexOf("-", 3) == 3)
                                || (domainPart.indexOf("-") == (domainPart.length() - 1))) {
                            status = false;
                            addMessage("hostname.DashCharacter");
                            break dowhile;
                        }

                        // Check each domain part
                        boolean checked = false;

                        for (int key = 0; key < regexChars.size(); key++) {
                            String regexChar = regexChars.get(key);
                            Pattern regex = Pattern.compile(regexChar);
                            Matcher regexMatcher = regex.matcher(domainPart);
                            status = regexMatcher.find();
                            if (status) {
                                int length = 63;

                                if (idnLength.containsKey(tld.toUpperCase())
                                        && idnLength.get(tld.toUpperCase()).containsKey(key)) {
                                    length = idnLength.get(tld.toUpperCase()).get(key);
                                }

                                int utf8Length;
                                try {
                                    utf8Length = domainPart.getBytes("UTF8").length;
                                    if (utf8Length > length) {
                                        addMessage("hostname.InvalidHostname");
                                    } else {
                                        checked = true;
                                        break;
                                    }
                                } catch (UnsupportedEncodingException ex) {
                                    Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
                                }


                            }
                        }


                        if (checked) {
                            ++check;
                        }
                    }

                    // If one of the labels doesn't match, the hostname is invalid
                    if (check != domainParts.length) {
                        status = false;
                        addMessage("hostname.InvalidHostnameSchema");

                    }
                } else {
                    // Hostname not long enough
                    status = false;
                    addMessage("hostname.UndecipherableTld");
                }

            } while (false);

            if (status == true && allowDNS) {
                result = true;
            }

        } else if (allowDNS == true) {
            addMessage("hostname.InvalidHostname");
            throw new ValidatorException(messages);
        }

        // Check input against local network name schema;
        Pattern regexLocal = Pattern.compile("^(([a-zA-Z0-9\\x2d]{1,63}\\x2e)*[a-zA-Z0-9\\x2d]{1,63}){1,254}$", Pattern.CASE_INSENSITIVE);
        boolean checkLocal = regexLocal.matcher(hostName).find();
        if (allowLocal && !status) {
            if (checkLocal) {
                result = true;
            } else {
                // If the input does not pass as a local network name, add a message
                result = false;
                addMessage("hostname.InvalidLocalName");
            }
        }


        // If local network names are not allowed, add a message
        if (checkLocal && !allowLocal && !status) {
            result = false;
            addMessage("hostname.LocalNameNotAllowed");
        }

        if (result == false) {
            throw new ValidatorException(messages);
        }

    }

    private void addMessage(String msg) {
        String bundlMsg = bundle.getString(msg);
        messages.add(new FacesMessage(FacesMessage.SEVERITY_ERROR, bundlMsg, bundlMsg));
    }

    /**
     * Returns a list of regex patterns for the matched TLD
     * @param tld
     * @return 
     */
    private List<String> getIdnRegexChars() {
        List<String> regexChars = new ArrayList<String>();
        regexChars.add("^[a-z0-9\\x2d]{1,63}$");
        Document doc = null;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);

        try {
            InputStream validIdns = getClass().getClassLoader().getResourceAsStream("com/myapp/resources/validIDNs_1.xml");
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(validIdns);
            doc.getDocumentElement().normalize();
        } catch (SAXException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        }

        // prepare XPath
        XPath xpath = XPathFactory.newInstance().newXPath();

        NodeList nodes = null;
        String xpathRoute = "//idn[tld=\'" + tld.toUpperCase() + "\']/pattern/text()";

        try {
            XPathExpression expr;
            expr = xpath.compile(xpathRoute);
            Object res = expr.evaluate(doc, XPathConstants.NODESET);
            nodes = (NodeList) res;
        } catch (XPathExpressionException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        }


        for (int i = 0; i < nodes.getLength(); i++) {
            regexChars.add(nodes.item(i).getNodeValue());
        }

        return regexChars;
    }

    /**
     * Decode Punycode string
     * @param encoded
     * @return 
         */
    private String decodePunycode(String encoded) {
        Pattern regex = Pattern.compile("([^a-z0-9\\x2d]{1,10})", Pattern.CASE_INSENSITIVE);
        Matcher matcher = regex.matcher(encoded);
        boolean found = matcher.find();

        if (encoded.isEmpty() || found) {
            // no punycode encoded string, return as is
            addMessage("hostname.CannotDecodePunycode");
            throw new ValidatorException(messages);
        }

        int separator = encoded.lastIndexOf("-");
            List<Integer> decoded = new ArrayList<Integer>();
        if (separator > 0) {
            for (int x = 0; x < separator; ++x) {
                decoded.add((int) encoded.charAt(x));
            }
        } else {
            addMessage("hostname.CannotDecodePunycode");
            throw new ValidatorException(messages);
        }

        int lengthd = decoded.size();
        int lengthe = encoded.length();

        // decoding
        boolean init = true;
        int base = 72;
        int index = 0;
        int ch = 0x80;

        int indexeStart = (separator == 1) ? (separator + 1) : 0;
        for (int indexe = indexeStart; indexe < lengthe; ++lengthd) {
            int oldIndex = index;
            int pos = 1;
            for (int key = 36; true; key += 36) {
                int hex = (int) encoded.charAt(indexe++);
                int digit = (hex - 48 < 10) ? hex - 22
                        : ((hex - 65 < 26) ? hex - 65
                        : ((hex - 97 < 26) ? hex - 97
                        : 36));

                index += digit * pos;
                int tag = (key <= base) ? 1 : ((key >= base + 26) ? 26 : (key - base));
                if (digit < tag) {
                    break;
                }
                pos = (int) (pos * (36 - tag));
            }
            int delta = (int) (init ? ((index - oldIndex) / 700) : ((index - oldIndex) / 2));
            delta += (int) (delta / (lengthd + 1));
            int key;
            for (key = 0; delta > 910; key += 36) {
                delta = (int) (delta / 35);
            }
            base = (int) (key + 36 * delta / (delta + 38));
            init = false;
            ch += (int) (index / (lengthd + 1));
            index %= (lengthd + 1);
            if (lengthd > 0) {
                for (int i = lengthd; i > index; i--) {
                    decoded.set(i, decoded.get(i - 1));
                }
            }

            decoded.set(index++, ch);
        }

        // convert decoded ucs4 to utf8 string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < decoded.size(); i++) {
            int value = decoded.get(i);
            if (value < 128) {
                sb.append((char) value);
            } else if (value < (1 << 11)) {
                sb.append((char) (192 + (value >> 6)));
                sb.append((char) (128 + (value & 63)));
            } else if (value < (1 << 16)) {
                sb.append((char) (224 + (value >> 12)));
                sb.append((char) (128 + ((value >> 6) & 63)));
                sb.append((char) (128 + (value & 63)));
            } else if (value < (1 << 21)) {
                sb.append((char) (240 + (value >> 18)));
                sb.append((char) (128 + ((value >> 12) & 63)));
                sb.append((char) (128 + ((value >> 6) & 63)));
                sb.append((char) (128 + (value & 63)));
            } else {
                addMessage("hostname.CannotDecodePunycode");
                throw new ValidatorException(messages);
            }
        }

        return sb.toString();

    }

    /**
     * Eliminates empty values from input array
     * @param data
     * @return 
     */
    private String[] verifyArray(String[] data) {
        List<String> result = new ArrayList<String>();
        for (String s : data) {
            if (!s.equals("")) {
                result.add(s);
            }
        }

        return result.toArray(new String[result.size()]);
    }
}

E un validIDNs.xml con schemi regex per i diversi tld (troppo grandi per includere :)

<idnlist>
    <idn>
        <tld>AC</tld>
        <pattern>^[\u002d0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>AR</tld>
        <pattern>^[\u002d0-9a-zà-ãç-êìíñ-õü]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>AS</tld>
        <pattern>/^[\u002d0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>AT</tld>
        <pattern>/^[\u002d0-9a-zà-öø-ÿœšž]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>BIZ</tld>
        <pattern>^[\u002d0-9a-zäåæéöøü]{1,63}$</pattern>
        <pattern>^[\u002d0-9a-záéíñóúü]{1,63}$</pattern>
        <pattern>^[\u002d0-9a-záéíóöúüőű]{1,63}$</pattern>
    </id>
</idlist>

Questa risposta non è più applicabile per ovvi motivi. Rimuovere la convalida TLD ed è probabilmente accettabile se si desidera accettare indirizzi di posta elettronica non inglesi.
Christopher Schneider,

3
public class Validations {

    private Pattern regexPattern;
    private Matcher regMatcher;

    public String validateEmailAddress(String emailAddress) {

        regexPattern = Pattern.compile("^[(a-zA-Z-0-9-\\_\\+\\.)]+@[(a-z-A-z)]+\\.[(a-zA-z)]{2,3}$");
        regMatcher   = regexPattern.matcher(emailAddress);
        if(regMatcher.matches()) {
            return "Valid Email Address";
        } else {
            return "Invalid Email Address";
        }
    }

    public String validateMobileNumber(String mobileNumber) {
        regexPattern = Pattern.compile("^\\+[0-9]{2,3}+-[0-9]{10}$");
        regMatcher   = regexPattern.matcher(mobileNumber);
        if(regMatcher.matches()) {
            return "Valid Mobile Number";
        } else {
            return "Invalid Mobile Number";
        }
    }

    public static void main(String[] args) {

        String emailAddress = "suryaprakash.pisay@gmail.com";
        String mobileNumber = "+91-9986571622";
        Validations validations = new Validations();
        System.out.println(validations.validateEmailAddress(emailAddress));
        System.out.println(validations.validateMobileNumber(mobileNumber));
    }
}

2

Se stai cercando di verificare se un indirizzo e-mail è valido, allora VRFY ti darà la possibilità. Ho trovato utile per la convalida di indirizzi Intranet (ovvero indirizzi e-mail per siti interni). Tuttavia è meno utile per i server di posta Internet (vedere le avvertenze nella parte superiore di questa pagina)


2

Sebbene ci siano molte alternative ai beni comuni di Apache, le loro implementazioni sono al massimo rudimentali (come l'implementazione dei beni comuni di Apache stessa ) e addirittura completamente sbagliate in altri casi.

Starei anche alla larga dalla cosiddetta regex 'non restrittiva'; non esiste nulla del genere. Ad esempio, @ è consentito più volte a seconda del contesto, come fai a sapere se c'è quello richiesto? Il regex semplice non lo capirà, anche se l'e-mail dovrebbe essere valida. Qualunque cosa più complessa diventa soggetta a errori o contiene persino performance killer nascoste . Come avete intenzione di mantenere qualcosa di simile a questo ?

L'unico validatore completo basato su regex conforme a RFC di cui sono a conoscenza è l' e-mail rfc2822-validator con il suo regex "raffinato" che si chiama appropriatamente Dragons.java . Supporta però solo le specifiche RFC-2822 precedenti , sebbene sufficientemente appropriate per le esigenze moderne (RFC-5322 le aggiorna in aree già fuori portata per i casi di utilizzo quotidiano).

Ma davvero quello che vuoi è un lexer che analizza correttamente una stringa e la suddivide nella struttura del componente secondo la grammatica RFC. EmailValidator4J sembra promettente al riguardo, ma è ancora giovane e limitato.

Un'altra opzione che hai è quella di utilizzare un servizio web come il servizio web di validazione testato da battaglia di Mailgun o l'API Mailboxlayer (appena preso i primi risultati di Google). Non è rigorosamente conforme a RFC, ma funziona abbastanza bene per le esigenze moderne.


1

Cosa vuoi convalidare? L'indirizzo email?

L'indirizzo e-mail può essere verificato solo per la sua conformità al formato. Vedi lo standard: RFC2822 . Il modo migliore per farlo è un'espressione regolare. Non saprai mai se esiste davvero senza inviare un'e-mail.

Ho controllato il validatore dei beni comuni. Contiene una classe org.apache.commons.validator.EmailValidator. Sembra essere un buon punto di partenza.


Non sono sicuro che il regex sia il modo migliore per farlo, è abbastanza illeggibile se si intende seguire la RFC alla lettera
user2813274

Concordo con @ user2813274, vorresti un lexer adeguato, non spaghetti regex.
Benny Bottema,

1

L'attuale versione di Apache Commons Validator è la 1.3.1 .

La classe che convalida è org.apache.commons.validator.EmailValidator. Ha un'importazione per org.apache.oro.text.perl.Perl5Util che proviene da un progetto ORO di Jakarta in pensione .

A proposito, ho scoperto che esiste una versione 1.4, ecco i documenti API . Sul sito dice: "Ultima pubblicazione: 05 marzo 2008 | Versione: 1.4-SNAPSHOT", ma non è definitiva. L'unico modo per costruirti (ma questa è un'istantanea, non RILASCIO) e utilizzare o scaricare da qui . Ciò significa che 1,4 non è stato reso definitivo per tre anni (2008-2011). Questo non è nello stile di Apache. Sto cercando un'opzione migliore, ma non ne ho trovata una molto adottata. Voglio usare qualcosa che è ben testato, non voglio colpire alcun bug.


1.4 SNAPSHOT richiede anche Jakarta ORO. Apache Commons Validator non è utilizzabile per me.
nebbia

Alla fine ho scelto Dr.Vet. La soluzione di Cumpanasu
mist

1
Sono d'accordo che il validatore di Apache Commons funziona bene, ma lo trovo piuttosto lento - oltre 3ms per chiamata.
Nic Cottrell,

Le prestazioni non sono così importanti per me.
nebbia

trunk corrente SNAPSHOT (SVN REV 1227719 a partire da ora) non ha più dipendenze esterne come ORO - non hai nemmeno più bisogno dell'intero modulo di validazione - le quattro classi org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator e RegexValidator è in grado di stare da solo
Jörg

0

Puoi anche verificare la lunghezza: le email hanno una lunghezza massima di 254 caratteri. Uso il validatore di Apache Commons e non lo controlla.


La specie RFC 2821 (sezione 4.5.3.1) specifica una local-partlunghezza di 64 e una domainlunghezza di 255. (Dicono che il permesso più lungo potrebbe essere rifiutato da altri software.)
sarnold

-2

Non sembrano esserci librerie o modi perfetti per farlo da soli, a meno che tu non abbia il tempo di inviare un'e-mail all'indirizzo e-mail e attendere una risposta (questa potrebbe non essere un'opzione però). Ho finito per usare un suggerimento da qui http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ e modificare il codice in modo che funzionasse in Java.

public static boolean isValidEmailAddress(String email) {
    boolean stricterFilter = true; 
    String stricterFilterString = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    String laxString = ".+@.+\\.[A-Za-z]{2}[A-Za-z]*";
    String emailRegex = stricterFilter ? stricterFilterString : laxString;
    java.util.regex.Pattern p = java.util.regex.Pattern.compile(emailRegex);
    java.util.regex.Matcher m = p.matcher(email);
    return m.matches();
}

-2

Questo è il metodo migliore:

public static boolean isValidEmail(String enteredEmail){
        String EMAIL_REGIX = "^[\\\\w!#$%&’*+/=?`{|}~^-]+(?:\\\\.[\\\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\\\.)+[a-zA-Z]{2,6}$";
        Pattern pattern = Pattern.compile(EMAIL_REGIX);
        Matcher matcher = pattern.matcher(enteredEmail);
        return ((!enteredEmail.isEmpty()) && (enteredEmail!=null) && (matcher.matches()));
    }

Fonti: - http://howtodoinjava.com/2014/11/11/java-regex-validate-email-address/

http://www.rfc-editor.org/rfc/rfc5322.txt


-2

Un'altra opzione è utilizzare il validatore e-mail di Hibernate , usando l'annotazione @Emailo usando la classe validatore a livello di codice, come:

import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; 

class Validator {
    // code
    private boolean isValidEmail(String email) {
        EmailValidator emailValidator = new EmailValidator();
        return emailValidator.isValid(email, null);
    }

}

Perché il downvote? È la stessa classe utilizzata da Hibernate Validator.
Dherik,

-3

Ecco il mio approccio pragmatico, dove voglio solo ragionevoli indirizzi blah @ domain distinti usando i caratteri consentiti dall'RFC. Gli indirizzi devono essere convertiti in minuscolo in anticipo.

public class EmailAddressValidator {

    private static final String domainChars = "a-z0-9\\-";
    private static final String atomChars = "a-z0-9\\Q!#$%&'*+-/=?^_`{|}~\\E";
    private static final String emailRegex = "^" + dot(atomChars) + "@" + dot(domainChars) + "$";
    private static final Pattern emailPattern = Pattern.compile(emailRegex);

    private static String dot(String chars) {
        return "[" + chars + "]+(?:\\.[" + chars + "]+)*";
    }

    public static boolean isValidEmailAddress(String address) {
        return address != null && emailPattern.matcher(address).matches();
    }

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.