Який найкращий метод перевірки електронної адреси Java? [зачинено]


247

Які хороші бібліотеки перевірки електронної адреси для Java? Чи існують альтернативи для спільноти валідатора ?


15
Я просто залишу це тут: davidcelis.com/blog/2012/09/06/…
mpenkov


Вам не слід використовувати бібліотеки (або регулярні вирази), які не всебічно перевіряють. Через складність дійсної адреси електронної пошти не існує середини між відсутністю перевірки та всебічною валідацією. Реалізація Apache Commons не є всебічною. Мені відомо лише одна бібліотека, яка є ( email-rfc2822-validator ), але вона все ще працює з величезними регулярними виразами. Комплексний лексер - це те, що ви дійсно хочете. EmailValidator4J каже, що це працює, але я не маю досвіду з цим.
Бенні Боттема

1
@BennyBottema Замість того, щоб редагувати питання з коментарями, будь ласка, напишіть мета-повідомлення, щоб обговорити, чому це було закрито, якщо у вас все ще є питання.
Machavity

Відповіді:


134

Apache Commons загалом відомий як надійний проект. Майте на увазі, однак, вам все одно доведеться надіслати електронний лист для підтвердження, якщо ви хочете переконатися, що це справжній електронний лист, і що власник хоче, щоб його використовували на вашому веб-сайті.

EDIT : Була помилка, в якій вона надто обмежувала домен, через що вона не приймала дійсні електронні листи з нових TLD.

Ця помилка була вирішена 03 / січня / 15 02:48 у commons-validator версії 1.4.1


1
Я погоджуюсь із цитатами, які ви цитували, але це частина проекту перевірки Commons?
duffymo

2
Ні, EmailValidatorклас Apache не надсилає електронне повідомлення для підтвердження.
Matthew Flaschen

3
Якщо вашим випадком використання є перевірка віддаленої адреси електронної пошти користувача, це рішення має значний недолік (подібний до InternetAddress.validate ()): EmailValidator розглядає користувача @ [10.9.8.7] як дійсні адреси електронної пошти, які вони відповідають RFC, але, можливо, не для реєстрації / контактної форми користувача.
zillion1

1
@zillion, що зафіксовано в Apache COmmons: "Ця програма не гарантується, щоб знайти всі можливі помилки в електронній пошті". І я сказав, що вам потрібно зробити, щоб "забезпечити справжню електронну пошту". Адреси з локальними ІС можуть бути дійсними в рідкісних умовах.
Меттью Флашен

5
Apache Commons EmailValidator має один серйозний недолік: не підтримує IDN.
Піохен

261

Використовувати офіційний пакет електронної пошти Java - це найпростіше:

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
Зауважте, що InternetAddress.validate () розглядає користувача @ [10.9.8.7] та user @ localhost як дійсні адреси електронної пошти - які вони відповідають RFC. Хоча, залежно від випадку використання (веб-форма), ви можете розглянути їх як недійсні.
zillion1

8
не тільки це справедливо як сказано @ zillion1, але й такі речі, як bla @ bla, вважаються дійсними. Дійсно, не найкраще рішення.
Дієго Пленц

4
@NicholasTolleyCottrell Це Java, тут ми кидаємо і виловлюємо винятки, я не дуже розумію вашу думку
gyorgyabraham

17
Я підозрюю, що конструктор InternetAddress був підроблений. Або моя система була підроблена. Або RFC822 було підроблено. Або я справді міг би спати зараз. Але я просто спробував якийсь код, і наступні п'ять рядків передаються як дійсні адреси електронної пошти, якщо ви передаєте їх конструктору InternetAddress, і "явно", вони невірні. Тут ми йдемо: ., .com, com., abcі 123. Крім того, додавання пробілу чи пробілу білого простору також не приводить до недійсності рядків. Ти будеш суддею!
Мартін Андерссон

4
гм, сир виходить з ладу, коли я його запускаю. до якого чорта бібліотека javax.mail ви посилаєтесь ???
Аарон Девідсон

91

Валідатор Apache Commons може використовуватися як зазначено в інших відповідях.

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 org.apache.commons.validator.routines.EmailValidator;

Код:

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

і дозволити місцеві адреси

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

2
В Android Studio ви можете додати компілювати "commons-validator: commons-validator: 1.4.1" у свій додаток \ залежність build.gradle {}
Benjiko99

2
Насправді, намагаючись створити мій проект, схоже, що апачі не дуже добре працюють з Android, сотні попереджень та деякі помилки, навіть не складені. Це те, що я закінчив за допомогою howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99

1
У мене така ж проблема, як і у Benjiko99. Після додавання залежності проект не збирається, говориться, java.exe закінчив з ненульовим кодом виходу 2.
Amit Mittal

1
Я також отримував помилки в Android Studio. Я змінив з 1.4.1 на 1.5.1 і це працює!
Метт

1
Примітка: Use_the Emailvalidator в org.apache.commons.validator.routines, оскільки EmailValidator в org.apache.commons.validator застарілий (я використовую 1.6 commons Validator)
HopeKing

71

Пізня відповідь, але я вважаю, що це просто і гідно:

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

Випробування :

введіть тут опис зображення

Для виробничих цілей перевірку доменних імен слід виконувати в мережі.


40
Це досить жорстокий спрощений валідатор, який ігнорує більшість правил RFC разом з IDN. Я б уникав цього для будь-якого додатка щодо якості виробництва.
mlaccetti

1
me@company.co.uk буде недійсним ...
Олександр Буракевич

14
Не скочуйте власний валідатор на основі регулярних виразів для речей, охоплених RFC.
Джош Гловер

6
винаходити колесо в порядку, якщо ви не заперечуєте над випадковою плоскою шиною
dldnh

це добре, але не для всіх випадків.
Андрейн

21

Якщо ви намагаєтеся перевірити форму, отриману від клієнта, або просто перевірку бобових - нехай це буде просто. Краще робити вільну перевірку електронної пошти, а не робити сувору та відхиляти деяких людей (наприклад, коли вони намагаються зареєструватися для вашого веб-сервісу). Оскільки майже все, що дозволено в частині електронної пошти електронної пошти та стільки нових доменів додаються буквально щомісяця (наприклад, .company, .entreprise, .estate), безпечніше не бути обмежувальним:

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

3
це справді хороший момент, будь-яке розумне додаток повинно мати інші заходи, щоб уникнути використання цього входу вниз по лінії
jmaculate

4
Як щодо змінити його на "^. + @. + (\\. [^ \\.] +) + $", Щоб уникнути крапки?
Xingang Huang

7

Пізно до запитання, ось, але: я підтримую клас за цією адресою: http://lacinato.com/cm/software/emailrelated/emailaddress

Він заснований на класі Les Hazlewood, але має численні вдосконалення та виправляє кілька помилок. Ліцензія Apache.

Я вважаю, що це найдієвіший аналізатор електронної пошти на Яві, і я ще не бачив ще одного здатного на будь-якій мові, хоча там може бути і один. Це не аналізатор у стилі лексера, але він використовує складний Java-регекс, і, таким чином, не настільки ефективний, як міг би бути, але моя компанія розібрала з ним понад 10 мільярдів реальних адрес: це, безумовно, корисно з високою продуктивністю ситуація. Можливо, раз на рік він потраплятиме на адресу, яка спричиняє переповнення стека регулярних виразів (відповідним чином), але це спам-адреси, довжиною яких є сотні чи тисячі символів, з багатьма цитатами та дужками тощо.

RFC 2822 та пов’язані з цим специфікації справді досить дозвільні з точки зору адрес електронної пошти, тому клас на кшталт цього є надмірним для більшості застосувань. Наприклад, наведена нижче законна адреса відповідно до специфікації, пробілів і всіх:

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

Жоден поштовий сервер не дозволив би цього, але цей клас може проаналізувати його (і переписати його у придатну форму).

Ми виявили існуючі параметри розбору електронної пошти Java недостатньо міцними (це означає, що всі вони не могли проаналізувати деякі дійсні адреси), тому ми створили цей клас.

Код добре задокументований і має безліч простих змін, щоб дозволити або заборонити певні форми електронної пошти. Він також пропонує безліч методів доступу до певних частин адреси (ліворуч, праворуч, особистих імен, коментарів тощо), для розбору / перевірки заголовків списку поштових скриньок, для аналізу / перевірки повернення шляху (що є унікальним серед заголовків) тощо.

Код, як написано, має javamail залежність, але його легко видалити, якщо ви не хочете незначної функціональності, яку він надає.


1
Привіт, я скопіював це у GitHub для публічної спільноти з відкритим кодом. Тепер кожен може коментувати, документувати та вдосконалювати код. github.com/bbottema/email-rfc2822-validator . Раніше Лес використовував старішу версію, але мені довелося її видалити через помилки, що заморожують регулярні вислови
Бенні Боттема,

7

Мені просто цікаво, чому ніхто не придумав @Emailдодаткових обмежень сплячого валідатора. Сам валідатор є EmailValidator.


Хоча альтернатива спільноті Apache, її реалізація є такою ж рудиментарною, як і більшість бібліотек на основі регулярних виразів. З документів: "Однак, оскільки ця стаття обговорює, не обов'язково практично реалізувати 100% сумісний валідатор електронної пошти". Єдиний всебічний валідатор, заснований на регулярних виразах, - це email-rfc2822-валідатор, інакше EmailValidator4J здається багатообіцяючим.
Бенні Боттема

5

Les Hazlewood написав дуже ретельний RFC 2822 сумісний клас валідатора електронної пошти, використовуючи регулярні вирази Java. Ви можете знайти його за адресою http://www.leshazlewood.com/?p=23 . Однак його ретельність (або реалізація Java RE) призводить до неефективності - читайте коментарі про час розбору довгих адрес.


1
Я побудував на відмінному класі Лез Хазлвуд (у якому є деякі помилки). (Дивіться мою окрему відповідь на це запитання.) Хоча я підтримував метод регулярного вираження Java, ми використовуємо його чудово в критичних для продуктивного середовища умовах. Якщо все, що ви робите, - це розбір адрес, продуктивність може бути проблемою, але для більшості користувачів я б підозрював, що це лише початок того, що вони роблять. Мої оновлення до класу також виправили ряд проблем із тривалими рекурсіями.
lacinato

Це застаріла бібліотека і двічі витісняється, нарешті, електронною поштою-rfc2822-валідатором . Хоча він все ще відповідає всім сучасним потребам, він все ще схильний до прихованих помилок продуктивності (і не підтримує обмежені зміни новішими специфікаціями RFC).
Бенні Боттема

3

Я переніс частину коду в 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();
    }
}

З валідатором імені хоста, як описано нижче:

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

І validIDNs.xml з шаблонами регулярних виразів для різних tlds (занадто великий, щоб включати :)

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

Ця відповідь із зрозумілих причин більше не застосовується. Видаліть перевірку TLD і, ймовірно, прийнятно, якщо ви бажаєте прийняти неанглійські адреси електронної пошти.
Крістофер Шнайдер

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

Якщо ви хочете перевірити, чи правдива адреса електронної пошти, то VRFY отримає вам частину шляху. Я виявив, що це корисно для перевірки адрес інтрамережі (тобто електронних адрес для внутрішніх сайтів). Однак це менш корисно для поштових серверів Інтернету (див. Застереження у верхній частині цієї сторінки)


2

Хоча існує багато альтернатив спільноті Apache, їх реалізація в кращому випадку є рудиментарною (як і сама реалізація Apache commons ), а в інших випадках - навіть неправильною.

Я б також не тримався осторонь так званого простого "не обмежуючого" виразу; такого немає. Наприклад, @ дозволено кілька разів залежно від контексту, як ти знаєш, що потрібна? Простий регулярний вираз не зрозуміє цього, хоча електронна пошта має бути дійсною. Все, що складніше, стає схильним до помилок або навіть містить приховані вбивці продуктивності . Як ви збираєтеся підтримувати що - щось на зразок цього ?

Єдиний всебічний валідатор, сумісний з RFC, про який я знаю, - це валідатор електронної пошти-rfc2822 з його «доопрацьованим» регулярним виразом, відповідним чином названим Dragons.java . Він підтримує лише старі специфікації RFC-2822, хоча, хоча й достатньо підходить для сучасних потреб (RFC-5322 оновлює його у районах, які вже не входять у сферу щоденного використання).

Але дійсно те, що ви хочете, - це лексер, який правильно розбирає рядок і розбиває його на структуру компонентів відповідно до граматики RFC. З цього приводу EmailValidator4J здається багатообіцяючим, але він все ще молодий і обмежений.

Інший варіант - використання веб-сервісу, такого як перевірена в бою веб- служба перевірки Mailgun або API поштової скриньки (тільки що взяли перші результати Google). Він не суворо сумісний з RFC, але працює досить добре для сучасних потреб.


1

Що ви хочете перевірити? Адреса електронної пошти?

Адресу електронної пошти можна перевірити лише на відповідність її формату. Дивіться стандарт: RFC2822 . Найкращий спосіб зробити це регулярний вираз. Ви ніколи не дізнаєтесь, чи дійсно існує, не надсилаючи електронний лист.

Я перевірив загальнодоступний валідатор. Він містить клас org.apache.commons.validator.EmailValidator. Це здається гарною відправною точкою.


Я не впевнений, що регулярний вираз - це найкращий спосіб зробити це, це зовсім нечитабельно, якщо ви маєте намір дотримуватися RFC до листа
user2813274

Погодьтеся з @ user2813274, ви б хотіли належного лексеру, а не регексу спагетті.
Бенні Боттема

1

Поточна версія валідатора Apache Commons - це 1.3.1 .

Клас, який підтверджує, - org.apache.commons.validator.EmailValidator. Він має імпорт для org.apache.oro.text.perl.Perl5Util, який є відставним проектом ORO в Джакарті .

До речі, я виявив, що є версія 1.4, ось документи API . На сайті написано: "Остання публікація: 05 березня 2008 | Версія: 1.4-SNAPSHOT", але це не остаточно. Єдиний спосіб створити себе (але це знімок, а не звільнення) та використовувати або завантажувати звідси . Це означає, що 1,4 не було остаточним протягом трьох років (2008–2011). Це не в стилі Apache. Я шукаю кращого варіанту, але не знайшов такого, який би дуже прийнятий. Я хочу використовувати те, що добре перевірено, не хочу потрапляти на помилки.


1.4 SNAPSHOT також вимагає Джакарта ORO. Apache Commons Validator не використовується для мене.
туман

Нарешті обрав Dr.Vet. Рішення Cumpanasu Florin: mkyong.com/regular-expressions/…
туман

1
Я погоджуюся, що валідатор Apache Commons працює добре, але я вважаю, що це досить повільно - понад 3 мс на дзвінок.
Нік Коттрелл

Продуктивність для мене не так важлива.
туман

поточний магістраль SNAPSHOT (SVN REV 1227719 відтепер) більше не має зовнішніх залежностей, таких як ORO - вам навіть не потрібен весь модуль перевірки - чотири класи org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator і RegexValidator вміє стояти окремо
Йорг

0

Ви також можете перевірити довжину - електронні листи мають довжину не більше 254 символів. Я використовую валідатор apache commons, і він не перевіряє це.


RFC 2821 вид (розділ 4.5.3.1) визначає local-partдовжину 64 та domainдовжину 255. (Вони кажуть, що довше дозволено, можливо, буде відхилено іншим програмним забезпеченням.)
sarnold

-2

Здається, немає ідеальних бібліотек або способів зробити це самостійно, якщо тільки вам не доведеться вчасно надсилати електронну пошту на електронну адресу і чекати відповіді (однак це може бути не можливим варіантом). Я в кінцевому підсумку скористався пропозицією звідси http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ і відкоригував код, щоб він працював на 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

Це найкращий метод:

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

Джерела: - http://howtodoinjava.com/2014/11/11/java-regex-validate-email-address/

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


-2

Іншим варіантом є використання валідатора електронної пошти Hibernate , використовуючи примітку @Emailабо використовуючи клас валідатора програмно, наприклад:

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

}

Чому потік? Це той самий клас, який використовує Hibernate Validator.
Дерік

-3

Ось мій прагматичний підхід, де я просто хочу розумно чітких адрес blah @ домену, використовуючи допустимі символи з RFC. Адреси потрібно попередньо перетворити на малі регістри.

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

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.