如何使用正則表達式得到一個 URL 中的主域名,不用正則還有什麼方法?
- world wide http://web.google.com returns http://google.com
- sub.domain http://names.are.awesome.google.com returns http://google.com
- http://doesntmatterhowlongasubdomainis.idont.wantit.google.com returns http://google.com
- http://sub.domain.google.com/no/thanks returns http://google.com
或者後端帶參數或者不帶參數都可以得到主域名,請問這個正則怎麼寫?
用正則表達式精準抽取「主域名」是做不到的。
舉個例子,給你 http://www.sina.com.cn 這樣的 URL,你覺得主域名是什麼呢?是 sina.com.cn 還是 com.cn 呢?
從常識來說,我們所希望得到的主域名,應該是能夠清晰區分網站主體的域名後綴,比如上面的例子,就是 http://sina.com.cn。那域名中的哪段內容才能區分網站主體呢?想一下就可以得出,是把整個域名從右往左分段,找到第一個「非公用」的部分。
首先,域名從右往左第一段是頂級域名(TLD),其中又分為通用頂級域名(gTLDs,如 .com、.edu、.org 等)和國家地區代碼頂級域名(ccTLDs,如 .cn、.uk、.hk 等)。ICANN 統一管理 gTLDs,並將 ccTLDs 下放給各種域名註冊機構管理,例如國家地區頂級域名就交由不同國家地區來管理。中國大陸的域名管理機構為著名的 CNNIC。我們再以 .cn 域名為例,下設一些預定義的「類別域名」如 .http://com.cn、.http://org.cn、.http://edu.cn 以及「行政區域名」如 .http://sh.cn、.http://bj.cn,並且同時開放 .cn 域名的註冊。這意味著,我註冊一個叫 test 的域名,既可以是 http://test.com.cn 也可以是 http://test.cn,也就是說,那些域名的「公用部分」長度是不確定的。那麼如果給我一個 URL 我是沒法以一個固定的方式來做截取的,而是必須知道這個 URL 的域名中哪個最長的後綴已經被某個域名管理機構預定義為公用的域名,然後剔除掉這部分才能找到第一個非公用的部分。
幸好,有 Public Suffix List 這樣的項目,你可以利用它提供的列表,來提取需要的「主域名」。目前的數據見:http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1。另外,你可以看看這個列表:Learn more about the Public Suffix List,看看都有誰在使用和維護這份數據,以及他們都用來幹嘛,比如:- Firefox 用來做瀏覽器地址欄的反釣魚(高亮顯示正確的「主域名」)
- Firefox 和 Chrome 都用其來進行 Cookie 相關的域名檢測
- Chrome 用來判斷用戶在地址欄輸入的是否是一個域名
從這個頁面你也可以看到,你用 JavaScript 的話,可以直接使用 tld.js 這個項目來提取主域名。
正則表達式無法做到準確,只能在某些前提條件下準確,你要有一定的錯誤容許。
比如 myname.pl, 在你確認這兒肯定是一個域名的時候,可以用正則匹配出這是一個域名;如果你連這兒是一個「域名」的前提條件都不確定,你是無法知道這是一個域名,還是一個perl腳本文件名的。
即使已經有了前提條件,還有一些問題需要解決:- 你要知道所有域名的後綴普通的有.com/.net/.org,奇特的有.jp、.in、.job、.tv、.telbtw,一級的後綴可以通過root zone的資料庫獲得
- 主域名有可能有兩個label普通的主域名是http://domain.com,可是很多後綴是兩個label的,比如工信部的網站http://www.miit.gov.cn,他的主域名是miit.gov.cn,後綴是gov.cn,當然cn的後綴還是net.cn、bj.cn、hb.cn,其實的一些cctld也有很多兩個label的後綴有多個label的後綴,無法通過root zone資料庫獲得
- IDN域名(多語言)上面多的都是ascii,這都弱爆了。有的域名是使用的中文,比如http://淘寶網.中國。中文的弱爆了,再搞個日文、俄語、希臘語、阿拉伯,你還能hold住么?
- newGTLD現在一級後綴是固定的,只有 IANA Root Zone Database 中的一些後綴。未來(現在已經開始)會增加成千上萬個新的後綴,像 .alibaba、.八卦、.。。。當然以後可能仍可以從 iana 的資料庫中獲取,但要記得更新哦,親
- IANA Root Zone Database: http://www.iana.org/domains/root/db
- CN域名的類別: http://www.cnnic.cn/ggfw/fwzx/bzzx/201206/t20120619_29881.htm#2_1
python 的解析庫在
https://pypi.python.org/pypi/publicsuffix/C#的在
https://github.com/danesparza/domainname-parserLearn more about the Public Suffix List 上沒列出來如果你只是需要在瀏覽器中通過JavaScript得到當前運行頁面的根域名的話,這樣:
/**
獲取到當前頁面的根域名用於設置cookie根域。
如:在www.sina.com.cn域下返回sina.com.cn
在video.sina.com.cn域下返回sina.com.cn
如果當前域名不是一個規範的域名,不包含dot時,如:localhost(方便在debug時使用)
則不會返回。因為在這種情況下設置cookie不需要再加domain(如果加了domain會導致在chrome下cookie設置不了)
@return {String} rootDomain
*/
var rootDomain = "";
function getCookieRootDomain() {
if (rootDomain) return rootDomain;
var d=location.host.split(":").shift().split("."),
tmpCookie,partDomain,
rdl=d.length;
if (rdl==1) {
return rootDomain="";
} else {
tmpCookie="TMP"+(+new Date);
while (rdl-- &> 2) {
partDomain=d.slice(1).join(".");
document.cookie=tmpCookie+"="+tmpCookie+"; domain="+partDomain;
tmpCookie=getCookie(tmpCookie);
document.cookie=tmpCookie+"=1; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain="+partDomain;
if (!tmpCookie) {
break;
}
d.shift();
}
return rootDomain=d.join(".");
}
}
function getCookie(name) {
var c=document.cookie,
start = c.indexOf(name+"=");
if (start==-1 || (start !~c.indexOf("; "+name+"="))) {
return "";
}
start = start+name.length+1;
var end = c.indexOf("; ",start);
if (end==-1) {end = c.length;}
return decodeURIComponent(c.substring(start,end));
}
沒有任何抽象規則能提取主域名。因為公共後綴是一個類似號碼簿的清單。
而且是變化的。
可以用PEG,寫起來比正則表示方便多了,有了這個你基本上可以丟棄regex了
給你個python的http://fdik.org/pyPEG/
一個lua的http://www.inf.puc-rio.br/~roberto/lpeg/其他語言自行搜索。如果你使用Java,建議可以使用guava搭配net包里的URL類。
guava
URL類可以提取出host,guava可以獲取頂級域名。
舉個例子:
public void urlTest() {
String urlstr = "http://1234.news.sina.com.cn/abc/dfe?sad=12sd=4";
try {
URL url = new URL(urlstr);
String host = url.getHost();
logger.info(host);
InternetDomainName domainName = InternetDomainName.from(host);
String top = domainName.topPrivateDomain().toString();
logger.info(top);
} catch (Exception e) {
logger.error(e);
}
}
輸出分別是:
1234.news.sina.com.cn
sina.com.cn
=========================================================
guava在最高票答案中的Learn more about the Public Suffix List也有推薦,這個功能僅僅是guava的一個功能,guava是個人認為是比較好用的一個庫,可以多加學習
(?i)(^https?://(?:w+.)*?)(w*.(?:com|club.cn|com|net|me|xyz))[/]*
有個缺點,域名後綴如果出現.info這種就沒辦法識別了,只能在正則中繼續添加匹配後綴的字元,例如:
(?i)(^https?://(?:w+.)*?)(w*.(?:com|club.cn|com|net|me|xyz|info))[/]*
urllib.parse?
(?&<=.)[^.]*.[^.]*$這個只能得到最後一個點前後的東西
比如 xxxx.123.sdd 得到123.sdd
xxxx.123.sdd.add 得到 sdd.add推薦閱讀:
※如何理解 "面向對象構建,函數式運行才是軟體開發的王道"?
※ES next中async/await proposal實現原理是什麼?
※angular directive 等controller執行完後再執行?
※一個優秀的前端工程師簡歷應該是怎樣的?
TAG:前端開發 | JavaScript | 正則表達式 |