2017-01-03 40 views
3

我想使用強調可讀性的算法驗證IPv6地址。理想的解決方案結合了簡單的正則表達式和源代碼。如何使用RegEx和代碼組合驗證IPv6地址?

https://blogs.msdn.microsoft.com/oldnewthing/20060522-08/?p=31113使用,例如:

function isDottedIPv4(s) 
{ 
    var match = s.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); 
    return match != null && 
     match[1] <= 255 && match[2] <= 255 && 
     match[3] <= 255 && match[4] <= 255; 
} 

通知如何雷蒙德從正則表達式移動複雜度成代碼。我希望有一個解決方案能夠爲IPv6提供相同的服務。

+0

[正則表達式匹配有效IPv6地址](// stackoverflow.com/a/ 17871737),[Javascript正則表達式驗證IPv4和IPv6地址,無主機名](// stackoverflow.com/q/2348 3855) – Tushar

+1

@Tushar我與您聯繫的解決方案與我所尋找的完全相反。如果您閱讀我提供的鏈接,您會看到我要求將正則表達式中的大部分複雜性移入​​源代碼中。 – Gili

+1

@Tushar請...閱讀我提供的鏈接。我的意思非常明確。基本上我想要一個只包含最小驗證捕獲組的正則表達式,以及驗證捕獲組的一段代碼。 – Gili

回答

3

這裏是Brandon's answer的變體:

/** 
 
* @param {String} a String 
 
* @return {Boolean} true if the String is a valid IPv6 address; false otherwise 
 
*/ 
 
function isIPv6(value) 
 
{ 
 
    // See https://blogs.msdn.microsoft.com/oldnewthing/20060522-08/?p=31113 and 
 
    // https://4sysops.com/archives/ipv6-tutorial-part-4-ipv6-address-syntax/ 
 
    const components = value.split(":"); 
 
    if (components.length < 2 || components.length > 8) 
 
    return false; 
 
    if (components[0] !== "" || components[1] !== "") 
 
    { 
 
    // Address does not begin with a zero compression ("::") 
 
    if (!components[0].match(/^[\da-f]{1,4}/i)) 
 
    { 
 
     // Component must contain 1-4 hex characters 
 
     return false; 
 
    } 
 
    } 
 

 
    let numberOfZeroCompressions = 0; 
 
    for (let i = 1; i < components.length; ++i) 
 
    { 
 
    if (components[i] === "") 
 
    { 
 
     // We're inside a zero compression ("::") 
 
     ++numberOfZeroCompressions; 
 
     if (numberOfZeroCompressions > 1) 
 
     { 
 
     // Zero compression can only occur once in an address 
 
     return false; 
 
     } 
 
     continue; 
 
    } 
 
    if (!components[i].match(/^[\da-f]{1,4}/i)) 
 
    { 
 
     // Component must contain 1-4 hex characters 
 
     return false; 
 
    } 
 
    } 
 
    return true; 
 
} 
 

 

 
console.log('Expecting true...'); 
 
console.log(isIPv6('2001:cdba:0000:0000:0000:0000:3257:9652')); 
 
console.log(isIPv6('2001:cdba:0:0:0:0:3257:9652')); 
 
console.log(isIPv6('2001:cdba::3257:9652')); 
 
console.log(isIPv6('2001:cdba::257:9652')); 
 
console.log(isIPv6('2001:DB8:0:2F3B:2AA:FF:FE28:9C5A')); 
 
console.log(isIPv6('::0:2F3B:2AA:FF:FE28:9C5A')); 
 
console.log('\n'); 
 
console.log('Expecting false...'); 
 
console.log(isIPv6(':0:2F3B:2AA:FF:FE28:9C5A'));

1

這仍然可能太複雜,但我認爲它涵蓋了大多數使用IPv6地址的場景。我最近經歷了類似的事情,很難用像IPv6這樣複雜的東西替換一個巨大的RegEx。

function isIPv6(s) 
 
{ 
 
    // Check if there are more then 2 : together (ex. :::) 
 
    if(/:{3,}/.test(s)) return false; 
 
    // Check if there are more then 2 :: (ex. ::2001::) 
 
    if(/::.+::/.test(s)) return false; 
 
    // Check if there is a single : at the end (requires :: if any) 
 
    if(/[^:]:$/.test(s)) return false; 
 
    // Check for leading colon 
 
    if(/^:(?!:)/.test(s)) return false; 
 
    // Split all the part to check each 
 
    var ipv6_parts = s.split(':'); 
 
    // Make sure there are at lease 2 parts and no more then 8 
 
    if(ipv6_parts.length < 2 || ipv6_parts.length > 8) return false; 
 
\t 
 
    var is_valid = true; 
 
    // Loop through the parts 
 
    ipv6_parts.forEach(function(part) { 
 
     // If the part is not blank (ex. ::) it must have no more than 4 digits 
 
    if(/^[0-9a-fA-F]{0,4}$/.test(part)) return; 
 
     // Fail if none of the above match 
 
    is_valid = false; 
 
    }); 
 
    
 
    return is_valid; 
 
} 
 

 
console.log(isIPv6('2001:cdba:0000:0000:0000:0000:3257:9652')); 
 
console.log(isIPv6('2001:cdba:0:0:0:0:3257:9652')); 
 
console.log(isIPv6('2001:cdba::3257:9652')); 
 
console.log(isIPv6('::2001:cdba:3257:9652'));

+0

這很聰明,但我認爲最後一次檢查應該允許1-4位數字。請參閱https://4sysops.com/archives/ipv6-tutorial-part-4-ipv6-address-syntax/中的「領先的零點抑制」...然後我相信你可以刪除if(part === 0)因爲它現在隱含了1-4位數的檢查。 – Gili

+0

增加了對領先0檢查的支持。 (part === 0)允許:0:這是有效的IPv6 – Brandon

+0

如果將'/ [0-9a-fA-F] {4} /。test(part)'更改爲'/ [0-9a- fA-F] {1,4} /。test(part)',那麼你可以刪除'部分=== 0'檢查。此外,目前您的代碼拒絕'2001:cdba :: 257:9652',我認爲這是合法的。最後,你的'forEach'循環的結果被忽略。如果它返回false,你的外部函數仍然返回true。 – Gili