Apa metode validasi alamat email Java terbaik? [Tutup]


247

Apa perpustakaan validasi alamat email yang baik untuk Java? Apakah ada alternatif untuk validator milik bersama ?


15
Saya hanya akan meninggalkan ini di sini: davidcelis.com/blog/2012/09/06/…
mpenkov


Anda seharusnya tidak ingin menggunakan perpustakaan (atau regex) yang tidak memvalidasi secara komprehensif. Karena kompleksitas alamat email yang valid, tidak ada jalan tengah antara tidak ada validasi dan validasi komprehensif. Implementasi Apache Commons tidak komprehensif. Saya menyadari hanya satu perpustakaan yang ( email-rfc2822-validator ), tetapi masih bekerja dengan regex besar. Lexer komprehensif adalah apa yang Anda inginkan. EmailValidator4J mengatakan itu berfungsi , tapi saya tidak punya pengalaman dengannya.
Benny Bottema

1
@ BennyBottema Alih-alih mengedit pertanyaan dengan komentar, silakan buat posting Meta untuk membahas mengapa ini ditutup jika Anda masih memiliki pertanyaan.
Machavity

Jawaban:


134

Apache Commons umumnya dikenal sebagai proyek yang solid. Namun perlu diingat, Anda masih harus mengirim email verifikasi ke alamat tersebut jika Anda ingin memastikan itu adalah email asli, dan bahwa pemilik ingin menggunakannya di situs Anda.

EDIT : Ada bug di mana itu terlalu ketat pada domain, menyebabkannya tidak menerima email yang valid dari TLD baru.

Bug ini diselesaikan pada 03 / Jan / 15 02:48 di commons-validator versi 1.4.1


1
Saya setuju dengan bit tambahan yang Anda kutip, tetapi apakah itu bagian dari proyek Validasi Commons?
duffymo

2
Tidak, EmailValidatorkelas Apache tidak mengirim pesan email untuk verifikasi.
Matthew Flaschen

3
Jika use case Anda adalah untuk memvalidasi alamat email jarak jauh pengguna, solusi ini memiliki kelemahan yang cukup besar (mirip dengan InternetAddress.validate ()): EmailValidator menganggap pengguna @ [10.9.8.7] sebagai alamat email yang valid - yang menurut mereka sesuai dengan RFC, tetapi mungkin tidak untuk pendaftaran / formulir kontak pengguna.
zillion1

1
@zillion, yang didokumentasikan dalam Apache COmmons: "Implementasi ini tidak dijamin untuk menangkap semua kesalahan yang mungkin terjadi pada alamat email." Dan saya katakan apa yang harus Anda lakukan untuk "memastikan email itu nyata". Alamat dengan IP lokal bisa valid di lingkungan yang langka.
Matthew Flaschen

5
Apache Commons EmailValidator memiliki satu kelemahan serius: tidak mendukung IDN.
Piohen

261

Menggunakan paket email resmi java adalah yang termudah:

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
Perhatikan bahwa InternetAddress.validate () menganggap pengguna @ [10.9.8.7] dan pengguna @ localhost sebagai alamat email yang valid - yang sesuai dengan RFC. Meskipun, tergantung pada kasus penggunaan (formulir web), Anda mungkin ingin menganggapnya tidak valid.
zillion1

8
tidak hanya itu valid seperti yang dikatakan @ zillion1, tetapi juga hal-hal seperti bla @ bla dianggap valid. Benar-benar bukan solusi terbaik.
Diego Plentz

4
@NicholasTolleyCottrell Ini adalah Jawa, di sini kita melempar dan menangkap pengecualian, saya tidak benar-benar mengerti maksud Anda
gyorgyabraham

17
Saya menduga bahwa konstruktor InternetAddress telah dirusak. Atau sistem saya telah dirusak. Atau RFC822 telah dirusak. Atau saya benar-benar bisa menggunakan tidur sekarang. Tapi saya baru saja mencoba beberapa kode dan lima string berikut semuanya lulus sebagai alamat email yang valid jika Anda meneruskannya ke konstruktor InternetAddress, dan "jelas", mereka tidak valid. Kita mulai:. , .com, com., abcdan 123. Juga, menambahkan spasi putih awal atau akhir juga tidak membatalkan string. Anda menjadi hakim!
Martin Andersson

4
um, keju gagal dengan benar ketika saya menjalankannya. apa perpustakaan javax.mail yang Anda tautkan ???
Aaron Davidson

91

Validator Apache Commons dapat digunakan seperti yang disebutkan dalam jawaban lain.

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'

Impor:

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

Kode:

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

dan untuk mengizinkan alamat lokal

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

2
Di Android Studio Anda dapat menambahkan kompilasi 'commons-validator: commons-validator: 1.4.1' ke dalam dependensi aplikasi Anda \ build.gradle {}
Benjiko99

2
Setelah benar-benar mencoba membangun proyek saya, tampaknya apache commons tidak berfungsi dengan baik pada Android, ratusan peringatan dan beberapa kesalahan, bahkan tidak dapat dikompilasi. Inilah yang akhirnya saya gunakan howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99

1
Masalah yang sama dengan saya pada Benjiko99. Setelah menambahkan dependensi, proyek tidak akan dikompilasi, kata java.exe selesai dengan kode keluar 2. nol
Amit Mittal

1
Saya juga mendapatkan kesalahan di Android Studio. Saya berubah dari 1.4.1 ke 1.5.1 dan berhasil!
Mat

1
Catatan: Use_the Emailvalidator di org.apache.commons.validator.routines sejak EmailValidator di org.apache.commons.validator tidak digunakan lagi (saya menggunakan Validator 1.6 commons)
HopeKing

71

Jawaban terlambat, tapi saya pikir itu sederhana dan layak:

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

Kasus uji :

masukkan deskripsi gambar di sini

Untuk tujuan produksi, validasi Nama Domain harus dilakukan berdasarkan jaringan.


40
Itu adalah validator yang sangat sederhana yang mengabaikan sebagian besar aturan RFC bersama dengan IDN. Saya akan menghindari ini untuk aplikasi kualitas produksi.
mlaccetti

1
me@company.co.uk tidak akan valid ...
Alexander Burakevych

14
Jangan gulung validator berbasis regex Anda sendiri untuk hal-hal yang dicakup oleh RFC.
Josh Glover

6
reinventing the wheel is OK asalkan Anda tidak keberatan dengan ban kempes sesekali
dldnh

itu baik tetapi tidak untuk semua kasus.
Andrain

21

Jika Anda mencoba melakukan validasi formulir yang diterima dari klien, atau hanya validasi kacang - sederhananya. Lebih baik untuk melakukan validasi email longgar daripada melakukan yang ketat dan menolak beberapa orang, (misalnya ketika mereka mencoba mendaftar untuk layanan web Anda). Dengan hampir semua hal diizinkan di bagian nama pengguna email dan begitu banyak domain baru ditambahkan secara harfiah setiap bulan (mis., Perusahaan, .repreprise, .estate), lebih aman untuk tidak membatasi:

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

3
ini adalah poin yang sangat bagus, aplikasi apa pun yang masuk akal harus memiliki langkah-langkah lain untuk mencegah input ini dieksploitasi di telepon
jmaculate

4
Bagaimana kalau mengubahnya menjadi "^. + @. + (\\. [^ \\.] +) + $" Untuk menghindari titik yang tertinggal?
Xingang Huang

7

Terlambat untuk pertanyaan, di sini, tetapi: Saya mempertahankan kelas di alamat ini: http://lacinato.com/cm/software/emailrelated/emailaddress

Ini didasarkan pada kelas Les Hazlewood, tetapi memiliki banyak perbaikan dan perbaikan beberapa bug. Lisensi Apache.

Saya percaya ini adalah pengurai email yang paling mampu di Jawa, dan saya belum melihat satu lagi yang mampu dalam bahasa apa pun, walaupun mungkin ada satu di luar sana. Ini bukan parser gaya-lexer, tetapi menggunakan beberapa regex java yang rumit, dan dengan demikian tidak seefisien mungkin, tetapi perusahaan saya telah mem-parsing lebih dari 10 miliar alamat dunia nyata dengan itu: tentu saja dapat digunakan dalam kinerja tinggi situasi. Mungkin setahun sekali akan mengenai alamat yang menyebabkan overflow tumpukan regex (tepat), tetapi ini adalah alamat spam yang panjangnya ratusan atau ribuan karakter dengan banyak kutipan dan tanda kurung dan sejenisnya.

RFC 2822 dan spesifikasi terkait benar-benar cukup permisif dalam hal alamat email, jadi kelas seperti ini berlebihan untuk sebagian besar penggunaan. Misalnya, berikut ini adalah alamat yang sah, sesuai dengan spesifikasi, spasi, dan semua:

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

Tidak ada server email yang mengizinkannya, tetapi kelas ini dapat menguraikannya (dan menulis ulang ke bentuk yang dapat digunakan).

Kami menemukan opsi pengurai email Java yang ada tidak cukup tahan lama (artinya, semuanya tidak dapat menguraikan beberapa alamat yang valid), jadi kami membuat kelas ini.

Kode ini didokumentasikan dengan baik dan memiliki banyak opsi yang mudah diubah untuk mengizinkan atau melarang formulir email tertentu. Ini juga menyediakan banyak metode untuk mengakses bagian tertentu dari alamat (sisi kiri, sisi kanan, nama pribadi, komentar, dll), untuk mengurai / memvalidasi header daftar kotak surat, untuk mengurai / memvalidasi jalur pengembalian (Yang unik di antara header), dan sebagainya.

Kode yang ditulis memiliki ketergantungan javamail, tetapi mudah untuk dihapus jika Anda tidak ingin fungsi kecil yang disediakannya.


1
Hai, saya menyalinnya ke GitHub untuk publik, komunitas sumber terbuka. Sekarang semua orang dapat berkomentar, mendokumentasikan, dan memperbaiki kodenya. github.com/bbottema/email-rfc2822-validator . Saya dulu menggunakan versi yang lebih lama oleh Les, tetapi saya harus menghapusnya karena bug pembekuan regex: leshazlewood.com/2006/11/06/emailaddress-java-class/…
Benny Bottema

7

Saya hanya ingin tahu mengapa tidak ada yang muncul @Emaildari kendala tambahan Hibernate Validator. Validator itu sendiri adalah EmailValidator.


Meskipun merupakan alternatif untuk Apache commons, implementasinya belum sempurna seperti kebanyakan perpustakaan berbasis regex. Dari dokumen: "Namun, ketika artikel ini membahas, belum tentu praktis untuk menerapkan validator email yang 100% patuh". Satu-satunya validator komprehensif berbasis regex yang saya tahu adalah email-rfc2822-validator dan sebaliknya EmailValidator4J tampaknya menjanjikan.
Benny Bottema

5

Les Hazlewood telah menulis kelas validator email sesuai RFC 2822 yang sangat teliti menggunakan ekspresi reguler Java. Anda dapat menemukannya di http://www.leshazlewood.com/?p=23 . Namun, ketelitiannya (atau implementasi Java RE) menyebabkan inefisiensi - baca komentar tentang waktu parsing untuk alamat yang panjang.


1
Saya membangun di atas kelas yang sangat baik Les Hazlewood (yang memang memiliki beberapa bug). (Lihat jawaban saya yang terpisah untuk pertanyaan ini.) Meskipun saya mempertahankan metode java regex, kami menggunakannya dengan baik di lingkungan yang kritis terhadap kinerja. Jika semua yang Anda lakukan adalah mengurai alamat, kinerjanya mungkin menjadi masalah, tetapi bagi sebagian besar pengguna saya menduga itu hanyalah awal dari apa pun yang mereka lakukan. Pembaruan saya ke kelas juga memperbaiki sejumlah masalah rekursi panjang.
Lacinato

Ini adalah perpustakaan yang sudah ketinggalan zaman dan telah digantikan dua kali, akhirnya oleh email-rfc2822-validator . Meskipun masih sesuai dengan semua kebutuhan modern, ia juga masih rentan terhadap bug kinerja tersembunyi (dan tidak mendukung perubahan terbatas oleh spesifikasi RFC yang lebih baru).
Benny Bottema

3

Saya mem-porting beberapa kode di 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();
    }
}

Dengan validator nama host sebagai berikut:

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

Dan validIDNs.xml dengan pola regex untuk tlds yang berbeda (terlalu besar untuk disertakan :)

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

Jawaban ini tidak berlaku lagi karena alasan yang jelas. Hapus validasi TLD dan mungkin diterima jika Anda ingin menerima alamat email non-Inggris.
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

Jika Anda ingin memverifikasi apakah alamat email itu valid, VRFY akan membantu Anda. Saya menemukan ini berguna untuk memvalidasi alamat intranet (yaitu, alamat email untuk situs internal). Namun itu kurang berguna untuk server surat internet (lihat peringatan di bagian atas halaman ini)


2

Meskipun ada banyak alternatif selain Apache commons, implementasinya belum sempurna (seperti implementasi Apache commons ' sendiri) dan bahkan salah dalam kasus lain.

Saya juga akan tinggal jauh dari apa yang disebut regex 'non-restriktif' sederhana; tidak ada hal seperti itu. Misalnya @ diizinkan beberapa kali tergantung pada konteks, bagaimana Anda tahu yang diperlukan ada di sana? Regex sederhana tidak akan memahaminya, meskipun email harus valid. Apa pun yang lebih kompleks menjadi rawan kesalahan atau bahkan mengandung pembunuh kinerja tersembunyi . Bagaimana Anda mempertahankan sesuatu seperti ini ?

Satu-satunya validator komprehensif berbasis regex yang sesuai dengan RFC yang saya ketahui adalah validator email-rfc2822 dengan regex 'yang disempurnakan' dengan tepat bernama Dragons.java . Ini hanya mendukung spesifikasi RFC-2822 yang lebih lama , meskipun cukup sesuai untuk kebutuhan modern ( pembaruan RFC-5322 di area yang sudah di luar ruang lingkup untuk kasus penggunaan sehari-hari).

Tapi sebenarnya yang Anda inginkan adalah lexer yang mem-parsing string dan memecahnya ke dalam struktur komponen sesuai dengan tata bahasa RFC. EmailValidator4J tampaknya menjanjikan dalam hal itu, tetapi masih muda dan terbatas.

Opsi lain yang Anda miliki adalah menggunakan layanan web seperti layanan web validasi pertarungan- mailgun atau API Mailboxlayer (hanya mengambil hasil Google pertama). Ini tidak sepenuhnya sesuai dengan RFC, tetapi berfungsi cukup baik untuk kebutuhan modern.


1

Apa yang ingin Anda validasi? Alamat email

Alamat email hanya dapat diperiksa untuk kesesuaian formatnya. Lihat standar: RFC2822 . Cara terbaik untuk melakukannya adalah ekspresi reguler. Anda tidak akan pernah tahu apakah benar-benar ada tanpa mengirim email.

Saya memeriksa validator milik bersama. Ini berisi kelas org.apache.commons.validator.EmailValidator. Tampaknya menjadi titik awal yang baik.


Saya tidak yakin regex adalah cara terbaik untuk melakukannya, cukup tidak terbaca jika Anda bermaksud mengikuti RFC ke surat itu
user2813274

Setuju dengan @ user2813274, Anda ingin lexer yang tepat, bukan regex spaghetti.
Benny Bottema

1

Versi Apache Commons Validator saat ini adalah 1.3.1 .

Kelas yang divalidasi adalah org.apache.commons.validator.EmailValidator. Ini memiliki impor untuk org.apache.oro.text.perl.Perl5Util yang berasal dari pensiunan proyek ORO Jakarta .

BTW, saya menemukan bahwa ada versi 1.4, di sini adalah dokumen API . Di situs itu tertulis: "Terakhir Diterbitkan: 05 Maret 2008 | Versi: 1.4-SNAPSHOT", tapi itu belum final. Satu-satunya cara untuk membangun diri sendiri (tetapi ini adalah snapshot, bukan RELEASE) dan gunakan, atau unduh dari sini . Ini berarti 1,4 belum dibuat final selama tiga tahun (2008-2011). Ini bukan gaya Apache. Saya mencari opsi yang lebih baik, tetapi tidak menemukan satu yang sangat diadopsi. Saya ingin menggunakan sesuatu yang sudah teruji dengan baik, tidak ingin menemukan bug.


1.4 SNAPSHOT juga membutuhkan ORO Jakarta. Apache Commons Validator tidak dapat digunakan untuk saya.
Kabut

Akhirnya memilih Dr.Vet. Solusi Cumpanasu Florin: mkyong.com/regular-expressions/…
mist

1
Saya setuju bahwa validator Apache Commons berfungsi dengan baik, tetapi saya merasa cukup lambat - lebih dari 3 ms per panggilan.
Nic Cottrell

Kinerja tidak begitu penting bagi saya.
Kabut

SNAPSHOT trunk saat ini (SVN REV 1227719 seperti sekarang) tidak lagi memiliki dependensi eksternal seperti ORO - Anda bahkan tidak memerlukan modul validasi keseluruhan lagi - empat kelas org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator dan RegexValidator dapat berdiri sendiri
Jorg

0

Anda mungkin juga ingin memeriksa panjangnya - email memiliki panjang maksimum 254 karakter. Saya menggunakan validator apache commons dan tidak memeriksa ini.


Spesies RFC 2821 (bagian 4.5.3.1) menetapkan local-partpanjang 64 dan domainpanjang 255. (Mereka mengatakan bahwa lebih lama diizinkan oleh mungkin ditolak oleh perangkat lunak lain.)
sarnold

-2

Sepertinya tidak ada perpustakaan yang sempurna atau cara untuk melakukan ini sendiri, kecuali jika Anda punya waktu untuk mengirim email ke alamat email dan menunggu jawaban (ini mungkin bukan pilihan). Saya akhirnya menggunakan saran dari sini http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ dan menyesuaikan kode sehingga akan berfungsi di Jawa.

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

Ini adalah metode terbaik:

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

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

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


-2

Pilihan lain adalah menggunakan validator email Hibernate , menggunakan anotasi @Emailatau menggunakan kelas validator secara terprogram, seperti:

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

}

Mengapa downvote? Ini kelas yang sama yang digunakan oleh Hibernate Validator.
Dherik

-3

Inilah pendekatan pragmatis saya, di mana saya hanya ingin alamat domain blah @ masuk akal yang berbeda menggunakan karakter yang diizinkan dari RFC. Alamat harus dikonversi menjadi huruf kecil terlebih dahulu.

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

}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.