【问题标题】:Detect URLs in text with JavaScript使用 JavaScript 检测文本中的 URL
【发布时间】:2010-12-02 18:48:54
【问题描述】:

有人对检测一组字符串中的 URL 有什么建议吗?

arrayOfStrings.forEach(function(string){
  // detect URLs in strings and do something swell,
  // like creating elements with links.
});

更新:我最终使用这个正则表达式进行链接检测……显然是几年后。

kLINK_DETECTION_REGEX = /(([a-z]+:\/\/)?(([a-z0-9\-]+\.)+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal))(:[0-9]{1,5})?(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(\s+|$)/gi

完整的助手(带有可选的 Handlebars 支持)位于 gist #1654670

【问题讨论】:

  • 尝试列出有限的 TLD 集可能不是一个好主意,因为它们会不断创建新的 TLD。
  • 同意。有时我们需要的是带有 TLD 的可更新代码。实际上可以构建脚本以将 TLD 附加到正则表达式或代码中的动态代码更新 TLD。生活中有些事情就像顶级域名和时区一样需要标准化。有限控制可能有助于验证真实世界地址用例的现有“TLD”可验证 URL。
  • 如果没有斜杠,这似乎不起作用? https://www.npmjs.com/package/linkifyjs 将失败,但 https://www.npmjs.com/package/linkifyjs/ 通过

标签: javascript regex url


【解决方案1】:

首先,您需要一个匹配 url 的良好正则表达式。这很难做到。见hereherehere

...几乎任何东西都是有效的 URL。那里 是一些标点符号规则 把它分开。没有任何 标点符号,你仍然有一个有效的 网址。

仔细检查 RFC,看看你是否 可以构造一个“无效”的 URL。这 规则非常灵活。

例如,::::: 是一个有效的 URL。 路径是":::::"。一个漂亮 愚蠢的文件名,但是一个有效的文件名。

另外,///// 是一个有效的 URL。这 netloc(“主机名”)是""。路径 是"///"。再次,愚蠢。还 有效的。此 URL 规范化为 "///" 这是等价的。

类似"bad://///worse/////" 是完全有效的。愚蠢但有效。

无论如何,这个答案并不是为了给你最好的正则表达式,而是证明如何使用 JavaScript 将字符串包装在文本中。

好的,让我们使用这个:/(https?:\/\/[^\s]+)/g

再次,这是一个糟糕的正则表达式。它会有很多误报。但是对于这个例子来说已经足够了。

function urlify(text) {
  var urlRegex = /(https?:\/\/[^\s]+)/g;
  return text.replace(urlRegex, function(url) {
    return '<a href="' + url + '">' + url + '</a>';
  })
  // or alternatively
  // return text.replace(urlRegex, '<a href="$1">$1</a>')
}

var text = 'Find me at http://www.example.com and also at http://stackoverflow.com';
var html = urlify(text);

console.log(html)
// html now looks like:
// "Find me at <a href="http://www.example.com">http://www.example.com</a> and also at <a href="http://stackoverflow.com">http://stackoverflow.com</a>"

总之试试:

$$('#pad dl dd').each(function(element) {
    element.innerHTML = urlify(element.innerHTML);
});

【讨论】:

  • 一些“许多误报”的例子会大大改善这个答案。否则,未来的 Google 员工只会留下一些(也许是有效的?)FUD。
  • 我从来不知道你可以将函数作为.replace 的第二个参数传递:|
  • 这很好,但它使用尾随标点符号 text="Find me at http://www.example.com, and also at http://stackoverflow.com." 会导致两个 404 错误。一些用户意识到了这一点,并会在 URL 之后的标点符号前添加一个空格以避免损坏,但我使用的大多数链接器(Gmail、etherpad、phabricator)将尾随标点符号与 URL 分开。
  • 如果文本已经包含锚定的 url,您可以使用 function removeAnchors(text) { var div = $('
    ').html(text); div.find('a').contents().unwrap();返回 div.text(); } 在返回 text.replace 之前首先删除锚点
  • 如果文本已经包含锚定的 url,您正在使用 jquery 删除锚点,但我使用的是 Angular。如何删除 Angular 中的锚点?
【解决方案2】:

这是我最终用作正则表达式的内容:

var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;

这不包括 URL 中的尾随标点符号。 Crescent 的功能就像一个魅力 :) 所以:

function linkify(text) {
    var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
    return text.replace(urlRegex, function(url) {
        return '<a href="' + url + '">' + url + '</a>';
    });
}

【讨论】:

  • 最后一个在最明显的情况下真正有效的正则表达式!这个值得收藏。我从谷歌搜索中测试了数千个示例,直到找到这个。
  • 简单又好看!但是 urlRegex 应该定义为 outside linkify 因为编译它很昂贵。
  • 无法检测到完整的 URL:disney.wikia.com/wiki/Pua_(Moana)
  • 我在每个字符列表中添加了(),现在可以使用了。
  • 它无法检测到仅以 www 开头的 url。例如:www.facebook.com
【解决方案3】:

我在谷歌上搜索了这个问题很长一段时间,然后我突然想到有一个 Android 方法 android.text.util.Linkify,它利用一些非常强大的正则表达式来完成这个。幸运的是,Android 是开源的。

他们使用几种不同的模式来匹配不同类型的网址。你可以在这里找到它们: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.0_r1/android/text/util/Regex.java#Regex.0WEB_URL_PATTERN

如果您只关心与 WEB_URL_PATTERN 匹配的 url,即符合 RFC 1738 规范的 url,则可以使用:

/((?:(http|https|Http|Https|rtsp|Rtsp):\/\/(?:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,64}(?:\:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,25})?\@)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\:\d{1,5})?)(\/(?:(?:[a-zA-Z0-9\;\/\?\:\@\&\=\#\~\-\.\+\!\*\'\(\)\,\_])|(?:\%[a-fA-F0-9]{2}))*)?(?:\b|$)/gi;

以下是原文全文:

"((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
+ "(?:"   // plus top level domain
+ "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ "|(?:biz|b[abdefghijmnorstvwyz])"
+ "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
+ "|d[ejkmoz]"
+ "|(?:edu|e[cegrstu])"
+ "|f[ijkmor]"
+ "|(?:gov|g[abdefghilmnpqrstuwy])"
+ "|h[kmnrtu]"
+ "|(?:info|int|i[delmnoqrst])"
+ "|(?:jobs|j[emop])"
+ "|k[eghimnrwyz]"
+ "|l[abcikrstuvy]"
+ "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
+ "|(?:name|net|n[acefgilopruz])"
+ "|(?:org|om)"
+ "|(?:pro|p[aefghklmnrstwy])"
+ "|qa"
+ "|r[eouw]"
+ "|s[abcdeghijklmnortuvyz]"
+ "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
+ "|u[agkmsyz]"
+ "|v[aceginu]"
+ "|w[fs]"
+ "|y[etu]"
+ "|z[amw]))"
+ "|(?:(?:25[0-5]|2[0-4]" // or ip address
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
+ "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+ "|[1-9][0-9]|[0-9])))"
+ "(?:\\:\\d{1,5})?)" // plus option port number
+ "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
+ "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+ "(?:\\b|$)";

如果您想真正花哨,您也可以测试电子邮件地址。电子邮件地址的正则表达式是:

/[a-zA-Z0-9\\+\\.\\_\\%\\-]{1,256}\\@[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25})+/gi

PS:上述正则表达式支持的顶级域截至 2007 年 6 月是最新的。有关最新列表,您需要查看https://data.iana.org/TLD/tlds-alpha-by-domain.txt

【讨论】:

  • 由于您有一个不区分大小写的正则表达式,您不必指定a-zA-Zhttp|https|Http|Https|rtsp|Rtsp
  • 这很好,但我不确定我是否会使用它。对于大多数用例,我宁愿接受一些误报,也不愿使用依赖硬编码 TLD 列表的方法。如果您在代码中列出 TLD,则可以保证它有一天会过时,如果可以避免的话,我宁愿不在我的代码中构建强制性的未来维护。
  • 这在 101% 的情况下都有效,不幸的是它还会找到前面没有空格的 url。如果我在 hello@mydomain.com 上运行匹配,它会捕获“mydomain.com”。有没有办法对此进行改进以仅在它前面有空格时才捕获它?
  • 还要注意,这非常适合捕获用户输入的网址
  • 请注意,grepcode.com 不再可用,here 是我认为 是指向 Android 源代码中正确位置的链接。我认为 Android 使用的正则表达式可能自 2013 年以来已更新(原始帖子),但似乎自 2015 年以来没有更新,因此可能缺少一些较新的 TLD。
【解决方案4】:

基于Crescent Fresh答案

如果您想检测 带有 http://不带 http:// 和 www. 的链接。您可以使用以下方法

function urlify(text) {
    var urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
    //var urlRegex = /(https?:\/\/[^\s]+)/g;
    return text.replace(urlRegex, function(url,b,c) {
        var url2 = (c == 'www.') ?  'http://' +url : url;
        return '<a href="' +url2+ '" target="_blank">' + url + '</a>';
    }) 
}

【讨论】:

  • 这是一个很好的解决方案,但我还想检查文本中是否应该已经包含 href。我试过这个正则表达式 = /((?!href)((https?:\/\/)|(www\.)|(mailto:))[^\s]+)/gi 但它不起作用。你能帮我解决这个问题吗,或者为什么上面的正则表达式不起作用。
  • 我很高兴您还在返回的输出中添加了 target="_blank"。这个版本是我想要的。没有什么太重要了(否则我会使用 Linkifyjs)足以获得大多数链接。
  • 这将匹配像 www.xyz 这样的重要网址
【解决方案5】:

NPM 上的这个库看起来挺全面的https://www.npmjs.com/package/linkifyjs

Linkify 是一个小而全面的 JavaScript 插件,用于查找纯文本 URL 并将其转换为 HTML 链接。它适用于所有有效的 URL 和电子邮件地址。

【讨论】:

  • 我刚刚在我的项目中实现了 linkifyjs,这太棒了。 Linkifyjs 应该是这个问题的答案。另一个要看的是github.com/twitter/twitter-text
【解决方案6】:

还可以进一步改进功能以渲染图像:

function renderHTML(text) { 
    var rawText = strip(text)
    var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;   

    return rawText.replace(urlRegex, function(url) {   

    if ( ( url.indexOf(".jpg") > 0 ) || ( url.indexOf(".png") > 0 ) || ( url.indexOf(".gif") > 0 ) ) {
            return '<img src="' + url + '">' + '<br/>'
        } else {
            return '<a href="' + url + '">' + url + '</a>' + '<br/>'
        }
    }) 
} 

或者对于链接到全尺寸图像的缩略图:

return '<a href="' + url + '"><img style="width: 100px; border: 0px; -moz-border-radius: 5px; border-radius: 5px;" src="' + url + '">' + '</a>' + '<br/>'

这里是 strip() 函数,它通过删除任何现有的 html 来预处理文本字符串以保持一致性。

function strip(html) 
    {  
        var tmp = document.createElement("DIV"); 
        tmp.innerHTML = html; 
        var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;   
        return tmp.innerText.replace(urlRegex, function(url) {     
        return '\n' + url 
    })
} 

【讨论】:

    【解决方案7】:

    已有npm包:url-regex,只需使用yarn add url-regexnpm install url-regex安装并使用如下:

    const urlRegex = require('url-regex');
    
    const replaced = 'Find me at http://www.example.com and also at http://stackoverflow.com or at google.com'
      .replace(urlRegex({strict: false}), function(url) {
         return '<a href="' + url + '">' + url + '</a>';
      });
    

    【讨论】:

      【解决方案8】:
      let str = 'https://example.com is a great site'
      str.replace(/(https?:\/\/[^\s]+)/g,"<a href='$1' target='_blank' >$1</a>")
      

      短代码大工作!...

      结果:-

       <a href="https://example.com" target="_blank" > https://example.com </a>
      

      【讨论】:

        【解决方案9】:

        如果您想检测带有 http:// 或不带 http:// 或 ftp 的链接或其他可能的情况(例如在末尾删除尾随标点符号),请查看此代码。

        https://jsfiddle.net/AndrewKang/xtfjn8g3/

        一个简单的使用方法就是使用 NPM

        npm install --save url-knife
        

        【讨论】:

          【解决方案10】:

          试试这个:

          function isUrl(s) {
              if (!isUrl.rx_url) {
                  // taken from https://gist.github.com/dperini/729294
                  isUrl.rx_url=/^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
                  // valid prefixes
                  isUrl.prefixes=['http:\/\/', 'https:\/\/', 'ftp:\/\/', 'www.'];
                  // taken from https://w3techs.com/technologies/overview/top_level_domain/all
                  isUrl.domains=['com','ru','net','org','de','jp','uk','br','pl','in','it','fr','au','info','nl','ir','cn','es','cz','kr','ua','ca','eu','biz','za','gr','co','ro','se','tw','mx','vn','tr','ch','hu','at','be','dk','tv','me','ar','no','us','sk','xyz','fi','id','cl','by','nz','il','ie','pt','kz','io','my','lt','hk','cc','sg','edu','pk','su','bg','th','top','lv','hr','pe','club','rs','ae','az','si','ph','pro','ng','tk','ee','asia','mobi'];
              }
          
              if (!isUrl.rx_url.test(s)) return false;
              for (let i=0; i<isUrl.prefixes.length; i++) if (s.startsWith(isUrl.prefixes[i])) return true;
              for (let i=0; i<isUrl.domains.length; i++) if (s.endsWith('.'+isUrl.domains[i]) || s.includes('.'+isUrl.domains[i]+'\/') ||s.includes('.'+isUrl.domains[i]+'?')) return true;
              return false;
          }
          
          function isEmail(s) {
              if (!isEmail.rx_email) {
                  // taken from http://stackoverflow.com/a/16016476/460084
                  var sQtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
                  var sDtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
                  var sAtom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
                  var sQuotedPair = '\\x5c[\\x00-\\x7f]';
                  var sDomainLiteral = '\\x5b(' + sDtext + '|' + sQuotedPair + ')*\\x5d';
                  var sQuotedString = '\\x22(' + sQtext + '|' + sQuotedPair + ')*\\x22';
                  var sDomain_ref = sAtom;
                  var sSubDomain = '(' + sDomain_ref + '|' + sDomainLiteral + ')';
                  var sWord = '(' + sAtom + '|' + sQuotedString + ')';
                  var sDomain = sSubDomain + '(\\x2e' + sSubDomain + ')*';
                  var sLocalPart = sWord + '(\\x2e' + sWord + ')*';
                  var sAddrSpec = sLocalPart + '\\x40' + sDomain; // complete RFC822 email address spec
                  var sValidEmail = '^' + sAddrSpec + '$'; // as whole string
          
                  isEmail.rx_email = new RegExp(sValidEmail);
              }
          
              return isEmail.rx_email.test(s);
          }
          

          还将识别诸如google.comhttp://www.google.blahttp://google.blawww.google.bla 等网址,但不能识别google.bla

          【讨论】:

            【解决方案11】:

            通用的面向对象解决方案

            对于像我这样使用不允许直接操作 DOM 的框架的人,我创建了一个函数,它接受一个字符串并返回一个 url/plainText 对象数组,可用于创建任何 UI你想要的表现形式。

            网址正则表达式

            对于我使用的 URL 匹配(略微改编)h0mayun 正则表达式:/(?:(?:https?:\/\/)|(?:www\.))[^\s]+/g

            我的函数还会从 URL 末尾删除标点符号,例如 .,答案解释得很好)为此,我将以下正则表达式应用于匹配的 URL /^(.+?)([.,?!'"]*)$/

            打字稿代码

                export function urlMatcherInText(inputString: string): UrlMatcherResult[] {
                    if (! inputString) return [];
            
                    const results: UrlMatcherResult[] = [];
            
                    function addText(text: string) {
                        if (! text) return;
            
                        const result = new UrlMatcherResult();
                        result.type = 'text';
                        result.value = text;
                        results.push(result);
                    }
            
                    function addUrl(url: string) {
                        if (! url) return;
            
                        const result = new UrlMatcherResult();
                        result.type = 'url';
                        result.value = url;
                        results.push(result);
                    }
            
                    const findUrlRegex = /(?:(?:https?:\/\/)|(?:www\.))[^\s]+/g;
                    const cleanUrlRegex = /^(.+?)([.,?!'"]*)$/;
            
                    let match: RegExpExecArray;
                    let indexOfStartOfString = 0;
            
                    do {
                        match = findUrlRegex.exec(inputString);
            
                        if (match) {
                            const text = inputString.substr(indexOfStartOfString, match.index - indexOfStartOfString);
                            addText(text);
            
                            var dirtyUrl = match[0];
                            var urlDirtyMatch = cleanUrlRegex.exec(dirtyUrl);
                            addUrl(urlDirtyMatch[1]);
                            addText(urlDirtyMatch[2]);
            
                            indexOfStartOfString = match.index + dirtyUrl.length;
                        }
                    }
                    while (match);
            
                    const remainingText = inputString.substr(indexOfStartOfString, inputString.length - indexOfStartOfString);
                    addText(remainingText);
            
                    return results;
                }
            
                export class UrlMatcherResult {
                    public type: 'url' | 'text'
                    public value: string
                }
            

            【讨论】:

              【解决方案12】:

              tmp.innerText 未定义。你应该使用 tmp.innerHTML

              function strip(html) 
                  {  
                      var tmp = document.createElement("DIV"); 
                      tmp.innerHTML = html; 
                      var urlRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;   
                      return tmp.innerHTML .replace(urlRegex, function(url) {     
                      return '\n' + url 
                  })
              

              【讨论】:

                【解决方案13】:

                您可以使用这样的正则表达式来提取正常的 url 模式。

                (https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})
                

                如果您需要更复杂的模式,请使用这样的库。

                https://www.npmjs.com/package/pattern-dreamer

                【讨论】:

                • (?:www\.|(?!www)) 的目的是什么?为什么wwwww.com 无效?
                • 你是对的。实际上我只是把它当作许多使用正则表达式的人。我建议使用上面的链接库。 url检测要考虑很多情况,所以正则表达式应该比较复杂。
                猜你喜欢
                • 2011-10-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-08-02
                • 1970-01-01
                相关资源
                最近更新 更多