子域的正则表达式

时间:2011-10-28 14:40:53

标签: regex

有没有人知道如何编写只允许 a-zA-Z0-9 .- (字母,数字,点和破折号)的正则表达式以点或短划线开头或结尾?

我试过这个:

/^[^.-][a-zA-Z0-9.-]+[^.-]$/

...但是如果我写一些类似“john @”的东西,那就行了,我不想这样做,因为@是不允许的。

9 个答案:

答案 0 :(得分:73)

子域

根据相关的互联网建议(RFC3986 section 2.2,后者又指:RFC1034 section 3.5RFC1123 section 2.1),子域名(DNS域名主机名的一部分),必须满足几个要求:

  • 每个子域名部分的长度不得超过63。
  • 每个子域名部分必须以字母数字开头和结尾(即字母[A-Za-z]或数字[0-9])。
  • 每个子域名部分可能包含连字符(破折号),但不能以连字符开头或结尾。

这是满足这些要求的子域部分的表达式片段:

[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?

请注意,此表达式片段不应单独使用 - 它需要在更大的上下文中合并边界条件,如下面的DNS主机名表达式所示...

DNS主机名

命名主机(不是IP地址)必须满足其他要求:

  • 主机名可能包含多个子域部分,每个部分用一个点分隔。
  • 整个主机名的长度不应超过255个字符。
  • 顶级域名(DNS主机名的最右侧部分)必须是国际公认的值之一。有效顶级域名列表由IANA.ORG维护。 (请参阅此处的简要当前列表:http://data.iana.org/TLD/tlds-alpha-by-domain.txt)。

考虑到这一点,这里有一个注释的正则表达式(在PHP语法中),它将伪验证DNS主机名:(请注意,这包含了子域的上述表达式的修改版本,并为此添加了注释)。

更新2016-08-20:由于此答案最初于2011年发布,因此顶级域名的数量已经爆炸。截至2016年8月,现在有超过1400个。这个答案的原始正则表达结合了所有这些,但这不是实用的。下面的新正则表达式包含顶级域的不同表达式。该算法来自:Top Level Domain Name Specification draft-liman-tld-names-06

$DNS_named_host = '%(?#!php/i DNS_named_host Rev:20160820_0800)
    # Match DNS named host domain having one or more subdomains.
    # See: http://stackoverflow.com/a/7933253/433790
    ^                     # Anchor to start of string.
    (?!.{256})            # Whole domain must be 255 or less.
    (?:                   # One or more sub-domains.
      [a-z0-9]            # Subdomain begins with alpha-num.
      (?:                 # Optionally more than one char.
        [a-z0-9-]{0,61}   # Middle part may have dashes.
        [a-z0-9]          # Starts and ends with alpha-num.
      )?                  # Subdomain length from 1 to 63.
      \.                  # Required dot separates subdomains.
    )+                    # End one or more sub-domains.
    (?:                   # Top level domain (length from 1 to 63).
      [a-z]{1,63}         # Either traditional-tld-label = 1*63(ALPHA).
    | xn--[a-z0-9]{1,59}  # Or an idn-label = Restricted-A-Label.
    )                     # End top level domain.
    $                     # Anchor to end of string.
    %xi';  // End $DNS_named_host.

请注意,此表达式并不完美。它需要一个或多个子域,但从技术上讲,主机可以包含没有子域的TLD(但这很少见)。

更新2014-08-12:为子域添加了简化表达式,不需要替换。

更新2016-08-20:修改后的DNS主机名正则表达式(更一般地说)与新的大量有效顶级域名相匹配。另外,从答案中删除了不必要的材料。

答案 1 :(得分:9)

您希望第一个和最后一个字符仅限于字母数字。你现在拥有的东西允许第一个和最后一个字符是点和破折号以外的任何字符。这符合以下描述:

/^[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9]$/

答案 2 :(得分:2)

在我们的项目中,我们匹配像这样的子域名

客户端JS

^([A-Za-z0-9](?:(?:[-A-Za-z0-9]){0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:(?:[-A-Za-z0-9]){0,61}[A-Za-z0-9])?){2,})$

服务器Ruby

\A([A-Za-z0-9](?:(?:[-A-Za-z0-9]){0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:(?:[-A-Za-z0-9]){0,61}[A-Za-z0-9])?){2,})\z

答案 3 :(得分:1)

试试这个:

/^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$/

但是字符串必须至少有2个字符才能匹配:a-zA-Z0-9和a-zA-Z0-9。为避免这种情况,您可以使用此正则表达式:

/^[a-zA-Z0-9][a-zA-Z0-9.-]*$/

但是你必须做一个额外的检查,以确保字符串的结尾既不是点也不是破折号。

答案 4 :(得分:1)

以下是 DOMAIN + SUBDOMAIN 解决方案,可能有助于其他人:

   /^([a-zA-Z0-9]([-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?\.)?([a-zA-Z0-9]{1,2}([-a-zA-Z0-9]{0,252}[a-zA-Z0-9])?)\.([a-zA-Z]{2,63})$/

通过以下chai测试:

const expect = require('chai').expect;

function testDomainValidNamesRegExp(val) {
    let names = /^([a-zA-Z0-9]([-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?\.)?([a-zA-Z0-9]([-a-zA-Z0-9]{0,252}[a-zA-Z0-9])?)\.([a-zA-Z]{2,63})$/;
    return names.test(val);
} 

let validDomainNames = [
    "example.com",
    "try.direct",
    "my-example.com",
    "subdomain.example.com",
    "example.com",
    "example23.com",
    "regexp-1222.org",
    "read-book.net",
    "org.host.org",
    "org.host.org",
    "velmart.shop-products.md",
    "ip2email.terronosp-222.lb",
    "stack.com",
    "sta-ck.com",
    "sta---ck.com",
    "9sta--ck.com",
    "sta--ck9.com",
    "stack99.com",
    "99stack.com",
    "sta99ck.com",
    "sub.do.com",
    "ss.sss-ss.ss",
    "s.sss-ss.ss",
    "s.s-s.ss",
    "test.t.te"
    ];

let invalidDomainNames = [
     "example2.com222",
     "@example.ru:?",
     "example22:89",
     "@jefe@dd.ru@22-",
     "example.net?1222",
     "example.com:8080:",
     ".example.com:8080:",
     "---test.com",
     "$dollars$.gb",
     "sell-.me",
     "open22.the-door@koll.ru",
     "mem-.wer().or%:222",
     "pop().addjocker.lon",
     "regular-l=.heroes?",
     " ecmas cript-8.org ",
     "example.com::%",
     "example:8080",
     "example",
     "examaple.com:*",
    "-test.test.com",
    "-test.com",
    "dd-.test.com",
    "dfgdfg.dfgdf33.e",
    "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd-.test.com",
    "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd.testttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt.com",
    "d-.test.com"
];

describe("Test Domain Valid Names RegExp", () => {
    validDomainNames.forEach((val) => {
        it(`Text: ${val}`, () => {
            expect(testDomainValidNamesRegExp(val)).to.be.true;
        });
    });
});

describe("Test Domain Invalid Names RegExp", () => {
    invalidDomainNames.forEach((val) => {
        it(`Text: ${val}`, () => {
            expect(testDomainValidNamesRegExp(val)).to.be.false;
        });
    });
});

非常欢迎更多测试!

答案 5 :(得分:0)

试试这个reg-exp /^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$/ 您的代码问题是[^.-]在开始和结束时匹配任何字符排除'。'或' - '匹配所有字符,而不一定是[a-zA-Z0-9]

答案 6 :(得分:0)

试试这个regex

^(?![-.])[a-zA-Z0-9.-]+(?<![-.])$

答案 7 :(得分:0)

这是子域的正则表达式

  • 在字符串中允许点(。),下划线(_),破折号(-)
  • 不允许在首个字符和最后一个字符中加点(。),下划线(_),破折号(-)
  • 允许字符串中的字母数字

    ^[a-zA-Z0-9]+[a-zA-Z0-9-._]*[a-zA-Z0-9]+$

正确的示例

  • abc.com
  • abc_xyz.com
  • abc.xyz.com
  • abc

不正确的示例

  • abc。
  • -abc
  • abc-
  • xyz.abc-
  • https://abcxyz.com

答案 8 :(得分:0)

如果您想要破折号但子域中没有点,请尝试此操作: /^\w[\w-]+\w$/