248

Các thư viện xác thực địa chỉ email tốt cho Java là gì? Có bất kỳ lựa chọn thay thế cho trình xác nhận commons ?

|
134

Apache Commons thường được biết đến như một dự án vững chắc. Tuy nhiên, xin lưu ý rằng bạn vẫn phải gửi email xác minh đến địa chỉ nếu bạn muốn đảm bảo đó là email thực và chủ sở hữu muốn sử dụng nó trên trang web của bạn.

EDIT : Có một lỗi trong đó quá hạn chế về tên miền, khiến nó không chấp nhận các email hợp lệ từ các TLD mới.

Lỗi này đã được giải quyết vào ngày 03/1/15 02:48 trong phiên bản commons-validator phiên bản 1.4.1

|
  • 1

    Tôi đồng ý với các bit bổ sung mà bạn đã trích dẫn, nhưng đó có phải là một phần của dự án Xác thực Commons không?

    – Lý Dũng Việt 00:33:24 09/03/2009
  • 1

    Không, EmailValidatorlớp Apache không gửi thông báo email để xác minh.

    – Hoàng Hoài Giang 18:34:59 14/07/2011
  • 1

    Nếu trường hợp sử dụng của bạn là để xác thực địa chỉ email từ xa của người dùng, giải pháp này có một lỗ hổng đáng kể (tương tự như InternetAddress.validate ()): EmailValidator coi người dùng @ [10.9.8.7] là địa chỉ email hợp lệ - mà họ đang theo RFC, nhưng có thể không cho đăng ký người dùng / mẫu liên hệ.

    – Hoàng Hạnh Nga 09:45:56 05/10/2011
  • 1

    @zillion, được ghi lại trong Apache COmmons: "Việc triển khai này không được đảm bảo để bắt tất cả các lỗi có thể có trong một địa chỉ email." Và tôi đã nói những gì bạn phải làm để "đảm bảo đó là một email thực sự". Tuy nhiên, địa chỉ với IP cục bộ có thể hợp lệ trong các môi trường hiếm.

    – Huỳnh Hữu Bảo 22:11:17 05/10/2011
  • 1

    Apache Commons EmailValidator có một nhược điểm nghiêm trọng: không hỗ trợ IDN.

    – Đặng Ngọc Oanh 10:50:41 05/06/2014
261

Sử dụng gói email java chính thức là dễ nhất:

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

    Lưu ý rằng InternetAddress.validate () coi người dùng @ [10.9.8.7] và người dùng @ localhost là địa chỉ email hợp lệ - theo địa chỉ RFC. Mặc dù, tùy thuộc vào trường hợp sử dụng (mẫu web), bạn có thể muốn coi chúng là không hợp lệ.

    – Lý Dũng Việt 08:30:33 05/10/2011
  • 1

    không chỉ có giá trị như @ zillion1 đã nói, mà cả những thứ như bla @ bla cũng được coi là hợp lệ. Thực sự không phải là giải pháp tốt nhất.

    – Hoàng Hoài Giang 17:30:01 20/11/2012
  • 1

    @NicholasTcarCottrell Đây là Java, ở đây chúng tôi ném và bắt ngoại lệ, tôi không thực sự hiểu ý của bạn

    – Hoàng Hạnh Nga 15:44:35 25/01/2013
  • 1

    Tôi nghi ngờ rằng nhà xây dựng InternetAddress đã bị giả mạo. Hoặc hệ thống của tôi đã bị giả mạo. Hoặc RFC822 đã bị giả mạo. Hoặc tôi thực sự có thể sử dụng một số giấc ngủ ngay bây giờ. Nhưng tôi chỉ thử một số mã và năm chuỗi sau đây đều chuyển qua dưới dạng địa chỉ email hợp lệ nếu bạn chuyển chúng cho nhà xây dựng InternetAddress và "rõ ràng", chúng không hợp lệ. Ở đây chúng ta đi: ., .com, com., abc123. Ngoài ra, việc thêm khoảng trắng ở đầu hoặc cuối cũng không làm mất hiệu lực của chuỗi. Bạn là thẩm phán!

    – Huỳnh Hữu Bảo 21:12:34 19/03/2013
  • 1

    um, phô mai thất bại đúng cách khi tôi chạy nó bạn đang liên kết đến thư viện javax.mail nào vậy ???

    – Đặng Ngọc Oanh 19:37:20 12/02/2015
91

Trình xác thực Apache Commons có thể được sử dụng như được đề cập trong các câu trả lời khác.

tệp pom.xml:

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

bản dựng.

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

Nhập khẩu:

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

Mật mã:

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

và cho phép địa chỉ địa phương

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

    Trong Android Studio, bạn có thể thêm biên dịch 'commons-validator: commons-validator: 1.4.1' vào ứng dụng của bạn \ build.gradle phụ thuộc {}

    – Lý Dũng Việt 17:08:26 11/12/2015
  • 1

    Sau khi thực sự cố gắng xây dựng dự án của tôi, có vẻ như apache commons không hoạt động tốt với Android, hàng trăm cảnh báo và một số lỗi, thậm chí nó còn không được biên dịch. Đây là những gì tôi đã kết thúc bằng cách sử dụng howtodoinjava.com/2014/11/11/java-regex-validate-email-address

    – Hoàng Hoài Giang 11:39:37 12/12/2015
  • 1

    Vấn đề tương tự với tôi là của Stewiko99. Sau khi thêm phần phụ thuộc, dự án sẽ không biên dịch, cho biết java.exe đã hoàn thành với mã thoát không bằng 0

    – Hoàng Hạnh Nga 21:01:15 18/03/2016
  • 1

    Tôi cũng đã nhận được lỗi trong Android Studio. Tôi đã thay đổi từ 1.4.1 thành 1.5.1 và nó hoạt động!

    – Huỳnh Hữu Bảo 22:20:45 11/10/2016
  • 1

    Lưu ý: Use_the Emailvalidator trong org.apache.commons.validator.routines kể từ EmailValidator trong org.apache.commons.validator không được chấp nhận (Tôi đang sử dụng Trình xác thực 1.6 commons)

    – Đặng Ngọc Oanh 03:55:47 22/12/2017
71

Câu trả lời muộn, nhưng tôi nghĩ nó đơn giản và xứng đáng:

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

Các trường hợp thử nghiệm :

Đối với mục đích sản xuất, xác thực tên miền nên được thực hiện theo mạng.

|
21

Nếu bạn đang cố gắng thực hiện xác nhận mẫu nhận được từ máy khách hoặc chỉ xác thực bằng bean - hãy giữ cho nó đơn giản. Tốt hơn là thực hiện xác thực email lỏng lẻo hơn là thực hiện nghiêm ngặt và từ chối một số người, (ví dụ: khi họ đang cố gắng đăng ký dịch vụ web của bạn). Với hầu hết mọi thứ được cho phép trong phần tên người dùng của email và rất nhiều tên miền mới được thêm vào mỗi tháng (ví dụ: công ty, .entreprise, .estate), sẽ an toàn hơn nếu không bị hạn chế:

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

    Đây là một điểm thực sự tốt, bất kỳ ứng dụng hợp lý nào cũng cần có các biện pháp khác để ngăn chặn đầu vào này không bị khai thác xuống dòng nào

    – Trịnh Diễm Hằng 18:04:47 12/12/2014
  • 1

    Làm thế nào về việc thay đổi nó thành "^. + @. + (\\. [^ \\.] +) + $" Để tránh dấu chấm?

    – Ngô Khắc Vũ 18:54:00 30/06/2015
7

Tôi chỉ tự hỏi tại sao không ai nghĩ ra @Emailtừ các ràng buộc bổ sung của Trình xác thực Hibernate. Trình xác nhận chính nó là EmailValidator.

|
  • 1

    Mặc dù là một thay thế cho Apache commons, nhưng việc triển khai nó cũng thô sơ như hầu hết các thư viện dựa trên regex. Từ các tài liệu: "Tuy nhiên, như bài viết này thảo luận, không nhất thiết phải thực hiện trình xác nhận email tuân thủ 100%". Trình xác nhận toàn diện dựa trên regex duy nhất mà tôi biết là email-rfc2822-validator và nếu không thì EmailValidator4J có vẻ đầy hứa hẹn.

    – Tạ Tuệ Lâm 08:50:37 29/12/2017
7

Cuối câu hỏi, nhưng: Tôi duy trì một lớp học tại địa chỉ này: http://lacinato.com/cm/software/emailrelated/emailaddress

Nó dựa trên lớp của Les Hazlewood, nhưng có nhiều cải tiến và sửa một vài lỗi. Giấy phép Apache.

Tôi tin rằng đây là trình phân tích email có khả năng nhất trong Java và tôi chưa thấy một trình duyệt nào có khả năng hơn trong bất kỳ ngôn ngữ nào, mặc dù có thể có một trình duyệt ngoài đó. Nó không phải là trình phân tích cú pháp kiểu lexer, nhưng sử dụng một số biểu thức java phức tạp và do đó không hiệu quả như nó có thể, nhưng công ty của tôi đã phân tích tốt hơn 10 tỷ địa chỉ trong thế giới thực với nó: nó chắc chắn có thể sử dụng được trong hiệu suất cao tình hình. Có thể mỗi năm một lần nó sẽ đánh vào một địa chỉ gây ra tràn ngăn xếp regex (một cách thích hợp), nhưng đây là những địa chỉ spam dài hàng trăm hoặc hàng nghìn ký tự với nhiều dấu ngoặc kép và dấu ngoặc đơn và tương tự.

RFC 2822 và các thông số kỹ thuật có liên quan thực sự khá dễ dàng về mặt địa chỉ email, vì vậy một lớp như thế này là quá mức cần thiết cho hầu hết các mục đích sử dụng. Ví dụ: sau đây là một địa chỉ hợp pháp, theo thông số kỹ thuật, khoảng trắng và tất cả:

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

Không có máy chủ thư nào cho phép điều đó, nhưng lớp này có thể phân tích cú pháp (và viết lại thành dạng có thể sử dụng được).

Chúng tôi thấy các tùy chọn trình phân tích cú pháp email Java hiện tại không đủ bền (có nghĩa là tất cả chúng không thể phân tích một số địa chỉ hợp lệ), vì vậy chúng tôi đã tạo lớp này.

Mã này được ghi chép tốt và có nhiều tùy chọn dễ thay đổi để cho phép hoặc không cho phép một số biểu mẫu email nhất định. Nó cũng cung cấp rất nhiều phương thức để truy cập vào một số phần của địa chỉ (phía bên trái, bên phải, tên cá nhân, nhận xét, v.v.), để phân tích / xác thực các tiêu đề danh sách hộp thư, để phân tích / xác thực đường dẫn (là duy nhất trong số các tiêu đề), v.v.

Mã như được viết có một phụ thuộc javamail, nhưng thật dễ dàng để loại bỏ nếu bạn không muốn chức năng nhỏ mà nó cung cấp.

|
5

Les Hazlewood đã viết một lớp trình xác nhận email tuân thủ RFC 2822 rất kỹ lưỡng bằng cách sử dụng các biểu thức chính quy Java. Bạn có thể tìm thấy nó tại http: // www . Meatazlewood.com/?p=23 . Tuy nhiên, tính kỹ lưỡng của nó (hoặc triển khai Java RE) dẫn đến không hiệu quả - đọc các nhận xét về thời gian phân tích cú pháp cho các địa chỉ dài.

|
  • 1

    Tôi xây dựng trên lớp xuất sắc của Les Hazlewood (có một số lỗi). (Xem câu trả lời riêng của tôi cho câu hỏi này.) Mặc dù tôi đã duy trì phương thức regex java, chúng tôi sử dụng nó tốt trong môi trường quan trọng về hiệu năng. Nếu tất cả những gì bạn đang làm là phân tích địa chỉ, hiệu suất có thể là một vấn đề, nhưng đối với hầu hết người dùng, tôi nghi ngờ đó chỉ là khởi đầu của bất cứ điều gì họ đang làm. Các cập nhật của tôi cho lớp cũng đã khắc phục một số vấn đề đệ quy dài.

    – Tạ Tuệ Lâm 06:41:04 30/10/2012
  • 1

    Đây là một thư viện lỗi thời và đã được thay thế hai lần, cuối cùng bởi email-rfc2822-validator . Mặc dù nó vẫn phù hợp với tất cả các nhu cầu hiện đại, nhưng nó vẫn dễ bị các lỗi hiệu năng ẩn (và không hỗ trợ các thay đổi hạn chế của thông số RFC mới hơn).

    – Tạ Thúy Đoan 10:06:14 29/12/2017
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));
    }
}
|
3

Tôi đã chuyển một số mã trong 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();
    }
}

Với trình xác nhận tên máy chủ như sau:

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

Và một tệp IDIDNs hợp lệ với các mẫu biểu thức chính quy cho các tld khác nhau (quá lớn để bao gồm :)

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

    Câu trả lời này không còn áp dụng được nữa vì những lý do rõ ràng. Xóa xác thực TLD và có thể chấp nhận được nếu bạn muốn chấp nhận các địa chỉ email không phải tiếng Anh.

    – Tạ Tuệ Lâm 13:09:45 14/04/2016
2

Một tùy chọn khác là sử dụng trình xác nhận email Hibernate , sử dụng chú thích @Emailhoặc sử dụng lớp trình xác nhận theo chương trình, như:

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

}
|
2

Đây là phương pháp tốt nhất:

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

Nguồn: - http://howtodoinjava.com/2014/11/11/java-regex-validate-email-address/

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

|
2

Dường như không có bất kỳ thư viện hay cách hoàn hảo nào để tự làm việc này, trừ khi bạn phải gửi email đến địa chỉ email và chờ phản hồi (mặc dù điều này có thể không phải là một lựa chọn). Tôi đã kết thúc bằng cách sử dụng một đề xuất từ ​​đây http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ và điều chỉnh mã để nó hoạt động trong 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

Mặc dù có nhiều lựa chọn thay thế cho commons Apache, nhưng việc triển khai của chúng là thô sơ nhất (như chính việc triển khai của Apache commons ) và thậm chí đã sai trong các trường hợp khác.

Tôi cũng sẽ tránh xa cái gọi là regex đơn giản 'không hạn chế'; không có những điều như vậy. Ví dụ @ được phép nhiều lần tùy thuộc vào ngữ cảnh, làm thế nào để bạn biết cái được yêu cầu ở đó? Regex đơn giản sẽ không hiểu nó, mặc dù email phải hợp lệ. Bất cứ điều gì phức tạp hơn đều trở nên dễ bị lỗi hoặc thậm chí có chứa các sát thủ hiệu suất ẩn . Làm thế nào bạn sẽ duy trì một cái gì đó như thế này ?

Trình xác nhận dựa trên regex tuân thủ RFC toàn diện duy nhất mà tôi biết là trình xác thực email-rfc2822 với regex 'được tinh chỉnh' có tên thích hợp là Dragons.java . Mặc dù vậy, nó chỉ hỗ trợ thông số RFC-2822 cũ hơn , mặc dù đủ thích hợp cho các nhu cầu hiện đại (RFC-5322 cập nhật nó trong các khu vực nằm ngoài phạm vi cho các trường hợp sử dụng hàng ngày).

Nhưng thực sự những gì bạn muốn là một từ vựng phân tích chính xác một chuỗi và chia nó thành cấu trúc thành phần theo ngữ pháp RFC. EmailValidator4J có vẻ đầy hứa hẹn về vấn đề đó, nhưng vẫn còn non trẻ và hạn chế.

Một tùy chọn khác mà bạn có là sử dụng dịch vụ web như dịch vụ web xác thực đã được kiểm tra trong trận chiến của Mailgun hoặc API Mailboxlayer (vừa lấy kết quả đầu tiên của Google). Nó không hoàn toàn tuân thủ RFC, nhưng hoạt động đủ tốt cho các nhu cầu hiện đại.

|
2

Nếu bạn đang tìm cách xác minh xem một địa chỉ email có hợp lệ hay không, thì VRFY sẽ giúp bạn tìm ra cách nào đó. Tôi thấy nó hữu ích khi xác thực địa chỉ mạng nội bộ (nghĩa là địa chỉ email cho các trang web nội bộ). Tuy nhiên, nó ít hữu ích hơn cho các máy chủ thư internet (xem phần lưu ý ở đầu trang này)

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.