正则表达式为子域

use*_*527 26 regex

有没有人知道怎么写一个只允许a-zA-Z0-9.-(字母,数字,点和破折号)的正则表达式但是从不以点或破折号开始或结束?

我试过这个:

/^[^.-][a-zA-Z0-9.-]+[^.-]$/
Run Code Online (Sandbox Code Playgroud)

...但是如果我写一些像"john @"这样的东西,那就行了,我不想,因为@是不允许的.

rid*_*ner 76

子域

根据相关的互联网建议(RFC3986第2.2节,反过来又指:RFC1034第3.5节RFC1123第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个.这个答案的原始正则表达包含了所有这些,但这并不是实用的.下面的新正则表达式包含顶级域的不同表达式.该算法来自:顶级域名规范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.
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • @algorhythm - 我对RFC的解释是双连字符完全有效,但每个子域部分可能不以连字符开头或结尾. (2认同)
  • 这是很好的粗略验证,但是 1. [下划线完全合法](/sf/answers/152819831/) 所以 `^\w(?:[\w-]{0,61}\w)子域部分的 ?$` 效果很好,事实上 [srv 记录需要它们](https://www.ietf.org/rfc/rfc2782.txt) 以避免与正常子域发生冲突 2. 仅供参考,双连字符是 [必需的为了 punycode](https://www.ietf.org/rfc/rfc3490.txt) 工作。当然,您可以将这些验证限制为某些记录类型,但是您必须为此编写一个小型解析器或其他东西,这也将允许您检查当前的顶级域名列表:) (2认同)

Dav*_*ber 9

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

/^[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9]$/
Run Code Online (Sandbox Code Playgroud)

  • 也许应该允许下划线(_).并且小注意:这个正则表达式可以简化为`/ ^\w [\ w .-] +\w $/i` (6认同)

Vas*_*cal 5

这是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})$/
Run Code Online (Sandbox Code Playgroud)

通过以下 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;
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

非常欢迎更多测试!