最近在補充基礎知識,看到了一道面試題 地址傳送點這裡 :
題目:解析一個完整的url,返回Object包含域與window.location相同
答案:
/**
* 解析一個url並生成window.location物件中包含的域
* location:
* {
* href: `包含完整的url`,
* origin: `包含協議到pathname之前的內容`,
* protocol: `url使用的協議,包含末尾的:`,
* username: `使用者名稱`, // 暫時不支援
* password: `密碼`, // 暫時不支援
* host: `完整主機名,包含:和埠`,
* hostname: `主機名,不包含埠`
* port: `埠號`,
* pathname: `伺服器上訪問資源的路徑/開頭`,
* search: `query string,?開頭`,
* hash: `#開頭的fragment identifier`
* }
*
* @param {string} url 需要解析的url
* @return {Object} 包含url資訊的物件
*/
function parseUrl(url) {
var result = {};
var keys = [`href`, `origin`, `protocol`, `host`,
`hostname`, `port`, `pathname`, `search`, `hash`];
var i, len;
var regexp = /(([^:]+:)//(([^:/?#]+)(:d+)?))(/[^?#]*)?(?[^#]*)?(#.*)?/;
var match = regexp.exec(url);
console.info(`match=`, match);
if (match) {
for (i = keys.length - 1; i >= 0; --i) {
result[keys[i]] = match[i] ? match[i] : ``;
}
}
console.info(`result=`, result);
return result;
}
parseUrl("http://test.com:8080?name=1&password=2#page1");
結果:
match=[
`http://test.com:8080?name=1&password=2#page1`,
`http://test.com:8080`,
`http:`,
`test.com:8080`,
`test.com`,
`:8080`,
undefined,
`?name=1&password=2`,
`#page1`,
index: 0,
input: `http://test.com:8080?name=1&password=2#page1`
]
result={
hash: `#page1`,
search: `?name=1&password=2`,
pathname: ``,
port: `:8080`,
hostname: `test.com`,
host: `test.com:8080`,
protocol: `http:`,
origin: `http://test.com:8080`,
href: `http://test.com:8080?name=1&password=2#page1`
}
複製程式碼
沒錯,一眼就看到了難以理解的是那段正規表示式:
/(([^:]+:)//(([^:/?#]+)(:d+)?))(/[^?#]*)?(?[^#]*)?(#.*)?/
複製程式碼
剛好最近看了精通正規表示式一書(的20%,哈哈看不完),剛好可以練練手了
1.匹配的陣列長度為11個,為什麼
2.每一個是怎麼匹配來的
首先,在分析之前,先給大家補補基礎概念,知道的就跳過
?: 匹配0個或一個
* 匹配0個或多個,
+: 一次或多次,至少出現一次
.* 貪婪匹配:在滿足匹配時,匹配儘可能長的字串,預設情況下,採用貪婪匹配(沒有問號)
// 非貪婪匹配:在滿足匹配時,匹配儘可能短的字串,使用?來表示非貪婪匹配
? 非貪婪,最小匹配(重點,後面會用到)
*? 重複任意次,但儘可能少重複
+? 重複1次或更多次,但儘可能少重複
?? 重複0次或1次,但儘可能少重複
{n,m}? 重複n到m次,但儘可能少重複
{n,}? 重複n次以上,但儘可能少重複
//環視
`jeffs`.replace(/(?<=jeff)(?=s)/i, `"`)
//順序環視和逆向環視,?= 匹配的目標位置後緊跟s,匹配的目標位置前緊鄰jeff jeff目標s,結果輸出:jeff"s
[^]: ^表示非 //示例:[^u]
//[]裡面的元字元只是普通字元
/03[-./]22/.test(`03-22`) 結果輸出:true
//() :標記一個子表示式的開始和結束位置。子表示式可以獲取供以後使用
複製程式碼
進入正題,匹配的陣列長度為11個,為什麼?
因為匹配結果是按照()的個數和順序決定的,重點是前面9個
最後兩個[index: 0,input: `http://test.com:8080?name=1&password=2#page1`]是regexp.exec函式自帶返回的
所以上面的表示式可以拆分為如下子表示式:
(([^:]+:)//(([^:/?#]+)(:d+)?))(/[^?#]*)?(?[^#]*)?(#.*)?
(([^:]+:)//(([^:/?#]+)(:d+)?))
([^:]+:)
(([^:/?#]+)(:d+)?)
([^:/?#]+)
(:d+)?
(/[^?#]*)?
(?[^#]*)?
(#.*)?
複製程式碼
具體分析見下圖:
思考題:
正規表示式分割之千分符格式:
213435324.099.toString().replace(/B(?=(d{3})+(?!d))/g, `,`)
複製程式碼
今天就到這裡,喜歡記得點贊~