가장 좋은 Java 이메일 주소 유효성 검사 방법은 무엇입니까? [닫은]


247

Java에 적합한 이메일 주소 유효성 검사 라이브러리는 무엇입니까? Commons Validator에 대한 대안이 있습니까?


15
나는 이것을 여기에 남겨 둘 것이다 : davidcelis.com/blog/2012/09/06/…
mpenkov


포괄적으로 검증되지 않은 라이브러리 (또는 정규식)를 사용하지 않아야합니다. 유효한 이메일 주소의 복잡성으로 인해 유효성 검사 없음과 포괄적 인 유효성 검사 사이에는 중간 점이 없습니다. Apache Commons의 구현은 포괄적 이지 않습니다 . 나는 ( email-rfc2822-validator ) 하나의 라이브러리 만 알고 있지만 여전히 거대한 정규식으로 작동합니다. 포괄적 인 어휘 분석기 는 당신이 정말로 원하는 것입니다. EmailValidator4J 는이 작업을 수행한다고 말했지만 경험이 없습니다.
베니 보 테마

1
@BennyBottema 주석으로 질문을 편집하는 대신 메타 게시물을 작성하여 여전히 질문이있는 경우 왜 닫혔는지 토론하십시오.
Machavity

답변:


134

Apache Commons는 일반적으로 견고한 프로젝트로 알려져 있습니다. 그러나 실제 이메일인지 확인하고 소유자가 사이트에서 사용하기를 원하는 경우에도 확인 이메일을 주소로 보내야합니다.

편집 : 도메인에 너무 제한적인 버그 가있어 새 TLD에서 유효한 전자 메일을받지 못합니다.

이 버그는 commons-validator 버전 1.4.1의 03 / Jan / 15 02:48에서 해결되었습니다.


1
나는 당신이 인용 한 여분의 비트에 동의하지만 Commons Validation 프로젝트의 일부입니까?
duffymo

2
아니요, Apache EmailValidator클래스는 확인을 위해 전자 메일 메시지를 보내지 않습니다.
Matthew Flaschen

3
사용 사례가 사용자의 원격 전자 메일 주소를 확인하는 경우이 솔루션에는 상당한 결함이 있습니다 (InternetAddress.validate ()와 유사). EmailValidator는 user @ [10.9.8.7]을 유효한 전자 메일 주소로 간주합니다. RFC이지만 사용자 등록 / 연락처 양식에는 적합하지 않습니다.
zillion1

1
@zillion은 Apache COmmons에 문서화되어 있습니다. "이 구현은 이메일 주소에서 가능한 모든 오류를 잡을 수는 없습니다." 그리고 "실제 이메일인지 확인"하기 위해해야 ​​할 일을 말했습니다. 로컬 IP가있는 주소는 드문 환경에서 유효 할 수 있습니다.
Matthew Flaschen

5
Apache Commons EmailValidator에는 한 가지 심각한 단점이 있습니다. IDN을 지원하지 않습니다.
Piohen

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 ()는 user @ [10.9.8.7] 및 user @ localhost를 RFC에 따른 유효한 전자 메일 주소로 간주합니다. 유스 케이스 (웹 양식)에 따라 유효하지 않은 것으로 취급 할 수 있습니다.
zillion1

8
@ zillion1이 말한 것처럼 유효 할뿐만 아니라 bla @ bla와 같은 것도 유효한 것으로 간주됩니다. 정말 최고의 솔루션은 아닙니다.
Diego Plentz

4
@NicholasTolleyCottrell 이것은 자바입니다, 여기서 우리는 예외를 던지고 잡습니다. 난 정말 당신의 요점을
알지 못합니다

17
InternetAddress 생성자가 변조 된 것 같습니다. 또는 내 시스템이 변조되었습니다. 또는 RFC822가 변조되었습니다. 아니면 지금 정말 잠을 잘 수도 있습니다. 그러나 방금 몇 가지 코드를 시도했으며 InternetAddress 생성자에 전달하면 다음 5 개의 문자열이 모두 유효한 전자 메일 주소로 전달되며 "확실히"유효하지 않습니다. 우리가 갈 여기 : ., .com, com., abc123. 또한 선행 또는 후행 공백을 추가해도 문자열이 무효화되지 않습니다. 당신은 판사입니다!
Martin Andersson

4
음, 치즈를 달릴 때 치즈가 제대로 작동하지 않습니다. 도대체 javax.mail 라이브러리는 무엇입니까?
Aaron Davidson

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'을 app \ build.gradle의 종속성 {}에 추가 할 수 있습니다.
Benjiko99

2
실제로 내 프로젝트를 빌드하려고 시도한 후에는 Apache 공통점이 Android에서 잘 작동하지 않는 것, 수백 가지 경고 및 일부 오류가 발생하여 컴파일조차하지 못했습니다. 이것은 내가 howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99

1
Benjiko99와 동일한 문제입니다. 의존성을 추가 한 후, 프로젝트는 컴파일되지 않을 것이라고 java.exe는 0이 아닌 종료 코드 2로 끝났다고 말합니다.
Amit Mittal

1
Android Studio에서도 오류가 발생했습니다. 1.4.1에서 1.5.1로 변경했는데 작동합니다!
Matt

1
참고 : org.apache.commons.validator의 EmailValidator가 더 이상 사용되지 않으므로 org.apache.commons.validator.routines의 Use_the Emailvalidator가 사용되지 않습니다 (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
그것은 IDN과 함께 대부분의 RFC 규칙을 무시하는 매우 잔인하게 간단한 유효성 검사기입니다. 나는 모든 프로덕션 품질 앱에서 이것을 피하려고합니다.
mlaccetti

1
me@company.co.uk는 유효하지 않습니다 ...
Alexander Burakevych 2016 년

14
RFC에서 다루는 것들에 대해 자신의 정규식 기반 유효성 검사기를 굴리지 마십시오.
Josh Glover

6
가끔 타이어가 마음에 들지 않는 한 휠의 재발견은 괜찮습니다
dldnh

그것은 좋지만 모든 경우에 해당되는 것은 아닙니다.
Andrain

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의 클래스를 기반으로하지만 많은 개선 사항이 있으며 몇 가지 버그가 수정되었습니다. 아파치 라이선스.

Java에서 가장 유능한 전자 메일 파서라고 생각하지만 아직 어떤 언어로도 유능한 전자 메일 파서가 하나도 보이지 않습니다. 그것은 렉서 스타일 파서가 아니지만 복잡한 자바 정규 표현식을 사용하므로 가능한 효율적이지 않지만 회사는 100 억 개 이상의 실제 주소를 파싱했습니다. 고성능으로 확실히 사용할 수 있습니다. 상태. 아마도 일년에 한 번은 정규 표현식 스택 오버플로를 유발하는 주소에 부딪 칠 수 있지만 (수많은 따옴표와 괄호 등으로 수백 또는 수천 자 길이의 스팸 주소입니다).

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 . Les의 이전 버전을 사용했지만 정규식 고정 버그로 인해 제거해야했습니다. leshazlewood.com/2006/11/06/emailaddress-java-class/…
Benny Bottema

7

왜 아무도 @EmailHibernate Validator의 추가 제약 조건을 생각해 냈는지 궁금 합니다. 유효성 검사기 자체는 EmailValidator입니다.


아파치 커먼즈에 대한 대안이지만, 그 구현은 대부분의 정규식 기반 라이브러리만큼 초보적입니다. 문서에서 : "그러나이 기사에서 설명하는 것처럼 100 % 호환 이메일 유효성 검사기를 구현하는 것이 반드시 실용적이지는 않습니다." 내가 아는 유일한 정규식 기반 종합 유효성 검사기는 email-rfc2822-validator 이며 EmailValidator4J 는 유망한 것으로 보입니다.
베니 보 테마

5

Les Hazlewood는 Java 정규식을 사용하여 매우 철저한 RFC 2822 호환 이메일 검사기 클래스를 작성했습니다. http://www.leshazlewood.com/?p=23 에서 찾을 수 있습니다 . 그러나 철저 함 (또는 Java RE 구현)으로 인해 비 효율성이 발생합니다. 긴 주소의 구문 분석 시간에 대한 주석을 읽으십시오.


1
나는 Les Hazlewood의 훌륭한 클래스를 만들었습니다 (버그가 있습니다). (이 질문에 대한 별도의 답변을 참조하십시오.) Java 정규식 방법을 유지 관리했지만 성능이 중요한 환경에서는 올바르게 사용합니다. 당신이하는 모든 것이 주소를 파싱하는 것이라면 성능이 문제가 될 수 있지만 대부분의 사용자에게는 그것이 그들이하는 일의 시작 일뿐이라고 생각합니다. 수업에 대한 나의 업데이트는 또한 많은 재귀 문제를 해결했습니다.
lacinato

이 라이브러리는 오래된 라이브러리이며 email-rfc2822-validator에 의해 두 번 대체되었습니다 . 여전히 모든 현대적인 요구에 맞지만 여전히 숨겨진 성능 버그가 발생하기 쉽습니다 (그리고 새로운 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()]);
    }
}

그리고 다른 tld에 대한 정규식 패턴이있는 validIDNs.xml (너무 포함하기에는 너무 큼)

<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 유효성 검사를 제거하고 허용 될 수 있습니다.
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

이메일 주소가 유효한지 확인하려면 VRFY 가 도움이 될 것입니다. 인트라넷 주소 (즉, 내부 사이트의 전자 메일 주소)를 확인하는 데 유용한 것으로 나타났습니다 . 그러나 인터넷 메일 서버에는 그다지 유용하지 않습니다 (이 페이지 상단의 경고 참조).


2

아파치 커먼즈에 대한 대안이 많이 있지만 아파치 커먼즈 구현 자체 와 같이 구현은 기본적으로 초보적 이며 다른 경우에는 잘못되었습니다.

나는 또한 간단한 '비 제한적'정규식에서 멀리 떨어져있을 것입니다. 그런 것은 없습니다. 예를 들어 @는 문맥에 따라 여러 번 허용됩니다 . 필요한 것이 있는지 어떻게 알 수 있습니까? 이메일이 유효하더라도 간단한 정규식으로 이해하지 못합니다. 아무것도 더 복잡 하게 오류가 발생하기 쉬운 또는 포함 숨겨진 성능 살인자 . 어떻게 같은 것을 유지하려고 ?

내가 아는 유일한 RFC 호환 정규식 기반 유효성 검사기 는 '정제 된'정규식으로 이름이 Dragons.java 인 email-rfc2822 유효성 검사기 입니다 . 최신 요구 사항에 충분히 적합하지만 이전 RFC-2822 사양 만 지원 합니다 (RFC-5322 는 이미 일상적인 사용 사례 범위를 벗어난 영역에서 업데이트 ).

그러나 실제로 원하는 것은 문자열을 올바르게 구문 분석하고 RFC 문법에 따라 구성 요소 구조로 나누는 렉서 입니다. EmailValidator4J 는 그 점에서 유망한 것처럼 보이지만 여전히 젊고 제한적입니다.

또 다른 옵션은 Mailgun의 전투 테스트 유효성 검사 웹 서비스 또는 Mailboxlayer API 와 같은 웹 서비스를 사용하는 것입니다 (첫 번째 Google 결과를 얻었습니다). RFC를 엄격하게 준수하지는 않지만 현대적인 요구에 적합합니다.


1

무엇을 확인 하시겠습니까? 이메일 주소?

전자 우편 주소는 형식 준수 여부 만 확인할 수 있습니다. 표준 RFC2822를 참조하십시오 . 가장 좋은 방법은 정규식입니다. 이메일을 보내지 않고 실제로 존재하는지 알 수 없습니다.

Commons Validator를 확인했습니다. org.apache.commons.validator.EmailValidator 클래스를 포함합니다. 좋은 출발점이 될 것 같습니다.


정규식이 그렇게하는 가장 좋은 방법인지 잘 모르겠습니다. RFC를 따라 편지를
보내려

@ user2813274에 동의하면 스파게티 정규식이 아닌 적절한 렉서를 원할 것입니다.
베니 보 테마

1

현재 Apache Commons Validator 버전은 1.3.1 입니다.

유효성을 검사하는 클래스는 org.apache.commons.validator.EmailValidator입니다. 은퇴 한 Jakarta ORO 프로젝트 에서 가져온 org.apache.oro.text.perl.Perl5Util에 대한 가져 오기 가 있습니다 .

BTW, 1.4 버전이 있음을 발견했습니다 . API 문서는 다음같습니다 . 이 사이트 에는 "최종 게시일 : 2008 년 3 월 5 일 | 버전 : 1.4-SNAPSHOT"이라고되어 ​​있지만 최종적인 것은 아닙니다. 자신을 구축하고 (RELEASE가 아닌 스냅 샷임) 유일한 방법은 여기 에서 사용하거나 다운로드 하십시오 . 이는 1.4 년이 3 년 동안 (2008-2011) 최종되지 않았 음을 의미합니다. 이것은 아파치 스타일이 아닙니다. 더 나은 옵션을 찾고 있지만 매우 채택 된 옵션을 찾지 못했습니다. 잘 테스트 된 것을 사용하고 싶습니다. 버그를 피하고 싶지 않습니다.


1.4 SNAPSHOT에는 자카르타 ORO도 필요합니다. Apache Commons Validator를 사용할 수 없습니다.
mist

마침내 Dr.Vet을 선택했습니다. Cumpanasu Florin의 솔루션 : mkyong.com/regular-expressions/…
mist

1
Apache Commons 유효성 검사기가 잘 작동한다는 데 동의하지만 호출 당 3ms 이상으로 상당히 느립니다.
Nic Cottrell

나에게는 성능이 그렇게 중요하지 않습니다.
08

현재 트렁크 SNAPSHOT (현재 SVN REV 1227719)에는 더 이상 ORO와 같은 외부 종속성이 없습니다. 더 이상 전체 유효성 검사 모듈이 필요하지 않습니다. 네 가지 클래스 org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator 및 RegexValidator는 혼자 서있을 수 있습니다
Jörg

0

길이를 확인하고 싶을 수도 있습니다. 이메일 길이는 최대 254 자입니다. 아파치 커먼즈 유효성 검사기를 사용하지만 이것을 확인하지 않습니다.


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가 사용하는 것과 같은 클래스입니다.
Dherik

-3

RFC의 허용 가능한 문자를 사용하여 합리적인 별개의 blah @ 도메인 주소를 원하는 실용적인 방법이 있습니다. 주소는 미리 소문자로 변환해야합니다.

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

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.