【问题标题】:Regexp for subdomain子域的正则表达式
【发布时间】:2011-12-17 08:40:38
【问题描述】:

有谁知道如何编写一个只允许 a-zA-Z0-9.-(字母、数字、点和破折号)的正则​​表达式以点或破折号开头还是结尾?

我试过这个:

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

...但是如果我写像“john@”这样的东西,它可以工作,我不想这样做,因为@是不允许的。

【问题讨论】:

  • 什么正则表达式的味道? (perl,egrep,awk,vim,javascript...)

标签: regex


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这是子域的正则表达式

    • 允许在字符串中使用点(.)、下划线(_)、破折号(-)
    • 不允许在第一个和最后一个字符中使用点 (.)、下划线 (_)、破折号 (-)
    • 允许在字符串中使用字母数字

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

    【讨论】:

      【解决方案3】:

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

      欢迎更多测试!

      【讨论】:

      • 这对我来说非常有效。仅供参考,我在末尾添加了以下内容,以便它可以获取端口号(如果存在)(在我的情况下,我们在本地使用它们时需要):(:[0-9]{0,4})?跨度>
      【解决方案4】:

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

      客户端 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
      

      【讨论】:

        【解决方案5】:

        子域

        根据相关的互联网建议(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 主机名:(请注意,这包含了上述子域表达式的修改版本,并在其中添加了 cmets )。

        2016 年 8 月 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 主机名正则表达式,以(更普遍地)匹配新的大量有效顶级域。此外,从答案中删除了不必要的材料。

        【讨论】:

        • 嗯,我认为双 '--' 也是无效的,但可以使用这个正则表达式,对吧?
        • @algorhythm - 我对 RFC 的解释是双连字符完全有效,但每个子域部分可能不以连字符开头或结尾。
        • 请注意,2016 年,允许的 TLD 比提供的 DNS 主机名正则表达式允许的要多得多。
        • @Qqwy - 是的,你是绝对正确的。当我有时间时,我会更新答案以反映这一点。感谢您的评论!
        • 这是一个很好的粗略验证,但是 1. underscores are perfectly legal 所以 ^\w(?:[\w-]{0,61}\w)?$ 用于子域部分工作得很好,实际上 srv records require them 以避免与正常子域发生冲突 2. 仅供参考双连字符是 @987654328 @ 去工作。您当然可以将这些验证限制为某些记录类型,但是您必须为此编写一个小型解析器,这也可以让您检查当前的 tld 列表:)
        【解决方案6】:

        试试这个regex:

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

        【讨论】:

          【解决方案7】:

          试试这个正则表达式/^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$/ 您的代码的问题是 [^.-] 在开头和结尾匹配任何字符 excpet '.'或 '-' 匹配所有字符,不一定是[a-zA-Z0-9]

          【讨论】:

            【解决方案8】:

            试试这个:

            /^[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.-]*$/
            

            但您必须进行额外检查以确保字符串的结尾既不是点也不是破折号。

            【讨论】:

              【解决方案9】:

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

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

              【讨论】:

              • 可能,也应该允许下划线 (_)。小注意:这个正则表达式可以简化为/^\w[\w.-]+\w$/i
              • 对于 PHP。感谢您的帮助,这个工作完美:[a-zA-Z0-9][a-zA-Z0-9\-\.]+[a-zA-Z0-9]
              • 在 test.subdomain..com 中失败
              • 此正则表达式对于 1 和 2 个字符的子域失败:a.domain.com、ab.domain.com
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-10-31
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多