Jaka jest najlepsza metoda sprawdzania poprawności adresu e-mail Java? [Zamknięte]


247

Jakie są dobre biblioteki sprawdzania poprawności adresów e-mail dla Java? Czy są jakieś alternatywy dla walidatora wspólnego ?




Nie powinieneś używać bibliotek (lub wyrażeń regularnych), które nie sprawdzają kompleksowo. Ze względu na złożoność prawidłowego adresu e-mail nie ma pośrednika między weryfikacją a kompleksową weryfikacją. Implementacja Apache Commons nie jest kompleksowa. Znam tylko jedną bibliotekę ( email-rfc2822-validator ), ale nadal działa z dużymi wyrażeniami regularnymi . Kompleksowy leksykon jest tym, czego naprawdę chcesz. EmailValidator4J mówi, że wykonuje swoją pracę, ale nie mam z tym doświadczenia.
Benny Bottema

1
@BennyBottema Zamiast edytować pytanie z komentarzem, proszę zamieścić post Meta, aby omówić, dlaczego został zamknięty, jeśli nadal masz pytania.
Machavity

Odpowiedzi:


134

Apache Commons jest ogólnie znany jako solidny projekt. Pamiętaj jednak, że nadal musisz wysłać weryfikacyjny adres e-mail na adres, jeśli chcesz mieć pewność, że jest to prawdziwy adres e-mail i że właściciel chce, aby był on używany w Twojej witrynie.

EDYCJA : Wystąpił błąd, który był zbyt restrykcyjny dla domeny, powodując, że nie akceptował prawidłowych e-maili z nowych TLD.

Ten błąd został rozwiązany 03 stycznia / 15 02:48 we wspólnym sprawdzaniu poprawności wersji 1.4.1


1
Zgadzam się z dodatkowymi bitami, które zacytowałeś, ale czy są one częścią projektu Commons Validation?
duffymo

2
Nie, EmailValidatorklasa Apache nie wysyła wiadomości e-mail w celu weryfikacji.
Matthew Flaschen

3
Jeśli Twoim przypadkiem użycia jest sprawdzenie poprawności zdalnego adresu e-mail użytkownika, to rozwiązanie ma znaczną wadę (podobnie jak InternetAddress.validate ()): EmailValidator uważa, że ​​użytkownik @ [10.9.8.7] jest prawidłowym adresem e-mail - są one zgodne z RFC, ale może nie do rejestracji użytkownika / formularza kontaktowego.
zillion1

1
@zillion, co jest udokumentowane w Apache COmmons: „Ta implementacja nie gwarantuje wyłapania wszystkich możliwych błędów w adresie e-mail”. Powiedziałem, co musisz zrobić, aby „upewnić się, że to prawdziwy e-mail”. Jednak adresy z lokalnymi adresami IP mogą być prawidłowe w rzadkich środowiskach.
Matthew Flaschen

5
Apache Commons EmailValidator ma jedną poważną wadę: nie obsługuje IDN.
Piohen

261

Korzystanie z oficjalnego pakietu e-mail Java jest najłatwiejsze:

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
Zauważ, że InternetAddress.validate () uważa użytkownika @ [10.9.8.7] i użytkownika @ localhost za prawidłowe adresy e-mail - które są zgodne z RFC. Jednak w zależności od przypadku użycia (formularz internetowy) możesz traktować je jako nieprawidłowe.
zillion1

8
nie tylko jest to poprawne, jak powiedział @ zillion1, ale również takie rzeczy jak bla @ bla są uważane za prawidłowe. Naprawdę nie najlepsze rozwiązanie.
Diego Plentz,

4
@NicholasTolleyCottrell To jest Java, tutaj rzucamy i łapiemy wyjątki, tak naprawdę nie rozumiem o co ci chodzi
gyorgyabraham 25.01.2013

17
Podejrzewam, że manipulowano konstruktorem InternetAddress. Albo mój system został zmieniony. Lub RFC822 został zmodyfikowany. Albo naprawdę mógłbym teraz trochę spać. Ale właśnie wypróbowałem trochę kodu, a następujące pięć ciągów znaków przekazuje jako prawidłowe adresy e-mail, jeśli przekażesz je konstruktorowi InternetAddress i „wyraźnie”, że nie są prawidłowe. Zaczynamy: ., .com, com., abci 123. Ponadto dodanie wiodących lub końcowych białych znaków również nie unieważnia ciągów. Ty jesteś sędzią!
Martin Andersson,

4
um, ser nie działa poprawnie, kiedy go uruchamiam. do jakiej biblioteki javax.mail do diabła łączysz?
Aaron Davidson,

91

Walidator Apache Commons może być używany jak wspomniano w innych odpowiedziach.

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'

Import:

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

Kod:

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

i zezwalać na adresy lokalne

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

2
W Android Studio możesz dodać kompilację „commons-validator: commons-validator: 1.4.1” do zależności aplikacji \ build.gradle {}
Benjiko99,

2
Po tym, jak faktycznie próbowałem zbudować mój projekt, wydaje się, że apache commons nie działa bardzo dobrze z Androidem, setki ostrzeżeń i niektóre błędy, nawet się nie skompilował. To właśnie skończyło się na howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99

1
Ten sam problem ze mną jak w przypadku Benjiko99. Po dodaniu zależności projekt się nie skompiluje, mówi java.exe zakończony niezerowym kodem wyjścia 2.
Amit Mittal

1
Pojawiały się również błędy w Android Studio. Zmieniłem z 1.4.1 na 1.5.1 i działa!
Matt

1
Uwaga: Use_the Emailvalidator w org.apache.commons.validator.routines od EmailValidator w org.apache.commons.validator jest przestarzały (używam 1.6 commons Validator)
HopeKing

71

Późna odpowiedź, ale myślę, że jest to proste i godne:

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

Przypadki testowe :

wprowadź opis zdjęcia tutaj

Do celów produkcyjnych weryfikację nazw domen należy przeprowadzać w sieci.


40
To dość brutalnie uproszczony walidator, który ignoruje większość reguł RFC wraz z IDN. Unikałbym tego w przypadku każdej aplikacji jakości produkcyjnej.
mlaccetti

1
me@company.co.uk nie będzie ważny ...
Alexander Burakevych,

14
Nie rzucaj własnym weryfikatorem opartym na wyrażeniach regularnych dla elementów objętych RFC.
Josh Glover,

6
wynalezienie koła jest OK, o ile nie przeszkadza ci okazjonalna płaska opona
dldnh 18.04.15

to jest dobre, ale nie we wszystkich przypadkach.
Andrain

21

Jeśli próbujesz przeprowadzić weryfikację formularza otrzymaną od klienta lub tylko weryfikację komponentu bean - zachowaj prostotę. Lepiej jest wykonać luźną weryfikację adresu e-mail niż ścisłą i odrzucić niektóre osoby (np. Kiedy próbują zarejestrować się w Twojej usłudze internetowej). Ponieważ prawie wszystko jest dozwolone w części e-mail dotyczącej nazwy użytkownika i tak wiele nowych domen jest dodawanych dosłownie każdego miesiąca (np. .Firma, .entreprise, .estate), bezpieczniej jest nie ograniczać:

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

3
to naprawdę dobry punkt, każda rozsądna aplikacja powinna mieć inne środki, aby zapobiec wykorzystaniu tego wkładu w
dalszym ciągu

4
Co powiesz na zmianę na „^. + @. + (\\. [^ \\.] +) + $”, Aby uniknąć kropki?
Xingang Huang,

7

Późno do pytania, tutaj, ale: Prowadzę zajęcia pod tym adresem: http://lacinato.com/cm/software/emailrelated/emailaddress

Opiera się na klasie Les Hazlewood, ale ma wiele ulepszeń i naprawia kilka błędów. Licencja Apache.

Wierzę, że jest to najbardziej wydajny parser wiadomości e-mail w Javie, i jeszcze nie widziałem jeszcze jednego zdolnego do działania w dowolnym języku, chociaż może istnieć taki. To nie jest parser w stylu leksykalnym, ale używa skomplikowanego wyrażenia regularnego java, a zatem nie jest tak wydajny, jak mógłby być, ale moja firma przeanalizowała z nim ponad 10 miliardów rzeczywistych adresów: z pewnością można go użyć w wysokiej wydajności sytuacja. Może raz w roku trafi na adres, który powoduje przepełnienie stosu wyrażeń regularnych (odpowiednio), ale są to adresy spamowe o długości setek lub tysięcy znaków z wieloma cytatami i nawiasami itp.

RFC 2822 i powiązane specyfikacje są naprawdę bardzo liberalne pod względem adresów e-mail, więc taka klasa jest nadmierna w przypadku większości zastosowań. Na przykład następujący adres jest zgodny z prawdą, zgodnie ze specyfikacją, spacjami i wszystkimi innymi:

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

Żaden serwer pocztowy nie pozwala na to, ale ta klasa może go parsować (i przepisać do użytecznej formy).

Odkryliśmy, że istniejące opcje parsera wiadomości e-mail Java są niewystarczająco trwałe (co oznacza, że ​​wszystkie nie mogły przeanalizować niektórych prawidłowych adresów), dlatego stworzyliśmy tę klasę.

Kod jest dobrze udokumentowany i ma wiele łatwych do zmiany opcji, które pozwalają lub nie zezwalają na niektóre formularze e-mail. Zapewnia również wiele metod dostępu do niektórych części adresu (lewa strona, prawa strona, imiona, komentarze itp.), Parsowania / sprawdzania poprawności nagłówków list skrzynek pocztowych, parsowania / sprawdzania ścieżki powrotnej (co jest unikalne wśród nagłówków) i tak dalej.

Jak napisano, kod jest zależny od javamail, ale łatwo go usunąć, jeśli nie chcesz, aby zapewniał on mniejszą funkcjonalność.


1
Cześć, skopiowałem go do GitHub dla publicznej społeczności open source. Teraz każdy może komentować, dokumentować i ulepszać kod. github.com/bbottema/email-rfc2822-validator . Kiedyś korzystałem ze starszej wersji Lesa, ale musiałem ją usunąć z powodu błędów zamrażania wyrażeń regularnych
Benny Bottema

7

Zastanawiam się tylko, dlaczego nikt nie wymyślił @Emaildodatkowych ograniczeń Hibernacji Validatora. Sam walidator to EmailValidator.


Chociaż jest to alternatywa dla wspólnych Apache, jego implementacja jest równie podstawowa, jak większość bibliotek opartych na wyrażeniach regularnych. Z dokumentów: „Jednak, jak omówiono w tym artykule, niekoniecznie jest praktyczne wdrożenie w 100% zgodnego modułu sprawdzania poprawności wiadomości e-mail”. Jedynym wszechstronnym weryfikatorem opartym na wyrażeniach regularnych, jaki znam, jest email-rfc2822-validator, a poza tym EmailValidator4J wydaje się obiecujący.
Benny Bottema

5

Les Hazlewood napisał bardzo dokładną klasę walidatora wiadomości e-mail zgodną z RFC 2822, używając wyrażeń regularnych Java. Można go znaleźć na stronie http://www.leshazlewood.com/?p=23 . Jednak jego dokładność (lub implementacja Java RE) prowadzi do nieefektywności - przeczytaj komentarze na temat czasów analizy dla długich adresów.


1
Zbudowałem na podstawie doskonałej klasy Les Hazlewood (która ma kilka błędów). (Zobacz moją osobną odpowiedź na to pytanie.) Mimo że zachowałem metodę wyrażenia regularnego java, używamy jej dobrze w środowisku krytycznym pod względem wydajności. Jeśli wszystko, co robisz, to parsowanie adresów, wydajność może być problemem, ale dla większości użytkowników podejrzewam, że to dopiero początek tego, co robią. Moje aktualizacje klasy rozwiązały również szereg problemów związanych z długą rekurencją.
lacinato,

Jest to przestarzała biblioteka i została dwukrotnie zastąpiona, w końcu przez email-rfc2822-validator . Mimo że wciąż spełnia wszystkie współczesne potrzeby, wciąż jest podatny na ukryte błędy wydajności (i nie obsługuje ograniczonych zmian w nowszych specyfikacjach RFC).
Benny Bottema

3

Przeniesiłem część kodu w 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();
    }
}

Z walidatorem nazwy hosta w następujący sposób:

@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()]);
    }
}

I validIDNs.xml z wzorcami wyrażeń regularnych dla różnych tlds (zbyt duże, aby je uwzględnić :)

<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>

Ta odpowiedź nie ma już zastosowania z oczywistych powodów. Usuń sprawdzanie poprawności TLD i prawdopodobnie jest to dopuszczalne, jeśli chcesz akceptować adresy e-mail w języku innym niż angielski.
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

Jeśli chcesz sprawdzić, czy adres e-mail jest prawidłowy, VRFY pomoże ci to zrobić. Przekonałem się, że jest to przydatne do sprawdzania poprawności adresów intranetowych (to znaczy adresów e-mail wewnętrznych stron). Jest to jednak mniej przydatne w przypadku serwerów poczty internetowej (patrz zastrzeżenia u góry tej strony)


2

Chociaż istnieje wiele alternatyw dla wspólnych aplikacji Apache, ich implementacje są co najwyżej podstawowe (podobnie jak implementacja wspólnych aplikacji Apache) sama ), a nawet w innych przypadkach są błędne.

Trzymałbym się również z dala od tak zwanego prostego wyrażenia „nieograniczającego”; Nie ma takiej rzeczy. Na przykład @ jest dozwolony wiele razy w zależności od kontekstu. Skąd wiesz, że wymagany jest tam? Proste wyrażenie regularne tego nie zrozumie, nawet jeśli e-mail powinien być prawidłowy. Wszystko bardziej złożone staje się podatne na błędy, a nawet zawiera ukryte narzędzia zabijające wydajność . Jak masz zamiar utrzymać coś jak to ?

Jedyny wszechstronny walidator oparty na wyrażeniach regularnych zgodny z RFC, o którym wiem, to email-rfc2822-validator z jego „dopracowanym” wyrażeniem regularnym odpowiednio nazwanym Dragons.java . Obsługuje tylko starszą specyfikację RFC-2822 , choć jest wystarczająco odpowiednia do współczesnych potrzeb (RFC-5322 aktualizuje ją w obszarach, które są już poza zasięgiem codziennych zastosowań).

Ale tak naprawdę to, czego potrzebujesz, to leksyk, który poprawnie analizuje ciąg i rozbija go na strukturę komponentu zgodnie z gramatyką RFC. EmailValidator4J wydaje się obiecujący pod tym względem, ale wciąż jest młody i ograniczony.

Inną opcją jest korzystanie z usługi internetowej, takiej jak sprawdzona w bitwie usługa walidacyjna Mailgun lub API Mailboxlayer (właśnie wziąłem pierwsze wyniki Google). Nie jest ściśle zgodny z RFC, ale działa wystarczająco dobrze dla współczesnych potrzeb.


1

Co chcesz sprawdzić? Adres e-mail?

Adres e-mail można sprawdzić tylko pod kątem zgodności z formatem. Zobacz standard: RFC2822 . Najlepszym sposobem na to jest wyrażenie regularne. Nigdy nie dowiesz się, czy naprawdę istnieje bez wysłania wiadomości e-mail.

Sprawdziłem wspólny walidator. Zawiera klasę org.apache.commons.validator.EmailValidator. Wydaje się być dobrym punktem wyjścia.


Nie jestem pewien, czy wyrażenie regularne jest najlepszym sposobem, aby to zrobić, jest to dość nieczytelne, jeśli zamierzasz zastosować RFC do listu
2813274

Zgadzam się z @ user2813274, chciałbyś mieć odpowiedni leksykon, a nie wyrażenia regularne spaghetti.
Benny Bottema

1

Aktualna wersja Apache Commons Validator to 1.3.1 .

Sprawdzana klasa to org.apache.commons.validator.EmailValidator. Ma import dla org.apache.oro.text.perl.Perl5Util, który pochodzi z wycofanego projektu ORO w Dżakarcie .

BTW, znalazłem, że istnieje wersja 1.4, oto dokumentacja API . Na stronie jest napisane: „Ostatnia publikacja: 05 marca 2008 | Wersja: 1.4-SNAPSHOT”, ale to nie koniec. Jedyny sposób na zbudowanie siebie (ale to migawka, a nie WYDANIE) i użycie lub pobranie stąd . Oznacza to, że wersja 1.4 nie została sfinalizowana przez trzy lata (2008-2011). To nie jest w stylu Apache. Szukam lepszej opcji, ale nie znalazłem takiej, która jest bardzo dobrze przyjęta. Chcę użyć czegoś, co jest dobrze przetestowane, nie chcę trafiać w żadne błędy.


1.4 SNAPSHOT wymaga również Dżakarta ORO. Walidator Apache Commons nie jest dla mnie przydatny.
mgła

Wreszcie wybrał Dr.Vet. Rozwiązanie Cumpanasu Florin: mkyong.com/regular-expressions/…
zamglenie

1
Zgadzam się, że walidator Apache Commons działa dobrze, ale uważam, że działa dość wolno - ponad 3 ms na połączenie.
Nic Cottrell,

Wydajność nie jest dla mnie tak ważna.
mgła

bieżący bagażnik SNAPSHOT (na razie SVN REV 1227719) nie ma już żadnych zewnętrznych zależności, takich jak ORO - nie potrzebujesz już nawet całego modułu sprawdzania poprawności - czterech klas org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator i RegexValidator jest w stanie pracować samodzielnie
Jörg

0

Możesz także sprawdzić długość - wiadomości e-mail mają maksymalnie 254 znaki. Używam sprawdzania poprawności wspólnego apache i nie sprawdza tego.


Gatunki RFC 2821 (sekcja 4.5.3.1) określają local-partdługość 64 i domaindługość 255. (Mówią, że dłuższe jest dozwolone przez może zostać odrzucone przez inne oprogramowanie.)
sarnold

-2

Wydaje się, że nie ma żadnych doskonałych bibliotek ani sposobów na zrobienie tego sam, chyba że musisz zdążyć wysłać wiadomość e-mail na adres e-mail i poczekać na odpowiedź (może to jednak nie być opcja). Skończyło się na tym, że skorzystałem z sugestii http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ i dostosowałem kod, aby działał w Javie.

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

To najlepsza metoda:

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

Źródła: - http://howtodoinjava.com/2014/11/11/java-regex-validate-email-address/

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


-2

Inną opcją jest użycie walidatora e-mail Hibernacja , użycie adnotacji @Emaillub programowe użycie klasy walidatora, na przykład:

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

}

Dlaczego głosowanie negatywne? Jest to ta sama klasa, z której korzysta Hibernate Validator.
Dherik

-3

Oto moje pragmatyczne podejście, w którym chcę tylko rozsądnych odrębnych adresów bla @ domain przy użyciu dopuszczalnych znaków z RFC. Adresy należy wcześniej przekonwertować na małe litery.

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

}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.