Excel VBA 是否为 Punycode 或转换为国际化域名的 Unicode/Ascii 提供任何类型的方法、函数或 API?
我能够找到似乎适用于 IDNA2008 标准的 JavaScript 版本(如下)。我仍然可以在 VBA 中使用它,但我认为这有点笨拙......
我尝试过的另一种方法是从在线 Punycode 转换器 ( http://www.unicode.org/cldr/utility/idna.jsp?a= ) 中抓取响应,但我真的对此并不感到疯狂,因为网站有时不可用,而且效率不高...
由于不同的网络浏览器(Internet Explorer、Firefox 和 Chrome)使用不同的标准。我需要能够使用所有标准(IDNA2003、UTS46、IDNA2008)在 Puny 之间进行转换,以便我可以生成/捕获所有可能的变化。
例如使用域“schüloß.de”我应该能够产生 2 个不同的变体:
统一码:
schüloss.de <- IDNA2003
schüloß.de <- IDNA2008
ASCII:
xn--schloss-p2a.de <- IDNA2003
xn--schlo-pqa4r.de <- IDNA2008
我不知道有任何 Web 对象或内置功能可以帮助处理 Punycode ...
有人会有一种可靠有效的方法来执行所有标准的 Punycode 转换吗?任何帮助将不胜感激。
Option Explicit
'code loosely based on 'http://stackoverflow.com/questions/5773683/excel-vba-parsed-json-object-loop
'Tools->References->
'MSScriptControl; Microsoft Script Control 1.0; {0E59F1D2-1FBE-11D0-8FF2-00A0D10038BC}; C:\Windows\SysWOW64\msscript.ocx
Private moScriptEngine As ScriptControl
Private Property Get ScriptEngine()
If moScriptEngine Is Nothing Then
Set moScriptEngine = New ScriptControl
moScriptEngine.Language = "JScript"
'moScriptEngine.AllowUI = True
End If
Set ScriptEngine = moScriptEngine
End Property
Private Function IDNA2008_JScript() As String
' toASCII = Unicode -> Punycode Example: ScriptEngine.Eval("punycode.toASCII('UNICODE')") = PUNYCODE
' toUnicode = Punycode -> Unicode Example: ScriptEngine.Eval("punycode.toUnicode('PUNYCODE')") = UNICODE
' TakenFrom: https://github.com/bestiejs/punycode.js/
IDNA2008_JScript = ";(function(root) { var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; var freeModule = typeof module == 'object' && module && !module.nodeType && module; var freeGlobal = typeof global == 'object' && global; " & _
"if ( freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal ) { root = freeGlobal;} var punycode, maxInt = 2147483647, base = 36, tMin = 1, tMax = 26, skew = 38, damp = 700, initialBias = 72, initialN = 128, " & _
"delimiter = '-', regexPunycode = /^xn--/, regexNonASCII = /[^\x20-\x7E]/, regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, errors = { 'overflow': 'Overflow: input needs wider integers to process', 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', 'invalid-input': 'Invalid input' }, " & _
"baseMinusTMin = base - tMin, floor = Math.floor, stringFromCharCode = String.fromCharCode, key; " & _
"function error(type) { throw new RangeError(errors[type]); } function map(array, fn) { var length = array.length; var result = []; while (length--) { result[length] = fn(array[length]); } return result; } " & _
"function mapDomain(string, fn) { var parts = string.split('@'); var result = ''; if (parts.length > 1) { result = parts[0] + '@'; string = parts[1]; } string = string.replace(regexSeparators, '\x2E'); var labels = string.split('.'); var encoded = map(labels, fn).join('.'); return result + encoded; } " & _
"function ucs2decode(string) { var output = [], counter = 0, length = string.length, value, extra; while (counter < length) { value = string.charCodeAt(counter++); if (value >= 0xD800 && value <= 0xDBFF && counter < length) { extra = string.charCodeAt(counter++); if ((extra & 0xFC00) == 0xDC00) { " & _
"output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); } else { output.push(value); counter--; } } else { output.push(value); } } return output; } function ucs2encode(array) { return map(array, function(value) { var output = ''; if (value > 0xFFFF) { " & _
"value -= 0x10000; output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); value = 0xDC00 | value & 0x3FF; } output += stringFromCharCode(value); return output; }).join(''); } function basicToDigit(codePoint) { if (codePoint - 48 < 10) { return codePoint - 22; } " & _
"if (codePoint - 65 < 26) { return codePoint - 65; } if (codePoint - 97 < 26) { return codePoint - 97; } return base; } function digitToBasic(digit, flag) { return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); } function adapt(delta, numPoints, firstTime) { var k = 0; delta = firstTime " & _
"? floor(delta / damp) : delta >> 1; delta += floor(delta / numPoints); for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { delta = floor(delta / baseMinusTMin); } return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); } function decode(input) { " & _
"var output = [], inputLength = input.length, out, i = 0, n = initialN, bias = initialBias, basic, j, index, oldi, w, k, digit, t, baseMinusT; basic = input.lastIndexOf(delimiter); if (basic < 0) { basic = 0; } for (j = 0; j < basic; ++j) { if (input.charCodeAt(j) >= 0x80) { error('not-basic'); } " & _
"output.push(input.charCodeAt(j)); } for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { for (oldi = i, w = 1, k = base; /* no condition */; k += base) { if (index >= inputLength) { error('invalid-input'); } digit = basicToDigit(input.charCodeAt(index++)); " & _
"if (digit >= base || digit > floor((maxInt - i) / w)) { error('overflow'); } i += digit * w; t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); if (digit < t) { break; } baseMinusT = base - t; if (w > floor(maxInt / baseMinusT)) { error('overflow'); } w *= baseMinusT; } " & _
"out = output.length + 1; bias = adapt(i - oldi, out, oldi == 0); if (floor(i / out) > maxInt - n) { error('overflow'); } n += floor(i / out); i %= out; output.splice(i++, 0, n); } return ucs2encode(output); } function encode(input) { var n, delta, handledCPCount, basicLength, bias, j, m, q, k, t, " & _
"currentValue, output = [], inputLength, handledCPCountPlusOne, baseMinusT, qMinusT; input = ucs2decode(input); inputLength = input.length; n = initialN; delta = 0; bias = initialBias; for (j = 0; j < inputLength; ++j) { currentValue = input[j]; if (currentValue < 0x80) { " & _
"output.push(stringFromCharCode(currentValue)); } } handledCPCount = basicLength = output.length; if (basicLength) { output.push(delimiter); } while (handledCPCount < inputLength) { for (m = maxInt, j = 0; j < inputLength; ++j) { currentValue = input[j]; " & _
"if (currentValue >= n && currentValue < m) { m = currentValue; } } handledCPCountPlusOne = handledCPCount + 1; if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { error('overflow'); } delta += (m - n) * handledCPCountPlusOne; n = m; for (j = 0; j < inputLength; ++j) { " & _
"currentValue = input[j]; if (currentValue < n && ++delta > maxInt) { error('overflow'); } if (currentValue == n) { for (q = delta, k = base; /* no condition */; k += base) { t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); if (q < t) { break; } qMinusT = q - t; baseMinusT = base - t; " & _
"output.push( stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) ); q = floor(qMinusT / baseMinusT); } output.push(stringFromCharCode(digitToBasic(q, 0))); bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); delta = 0; ++handledCPCount; } } " & _
"++delta; ++n; } return output.join(''); } function toUnicode(input) { return mapDomain(input, function(string) { return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string; }); } function toASCII(input) { return mapDomain(input, function(string) { " & _
"return regexNonASCII.test(string) ? 'xn--' + encode(string) : string; }); } punycode = { 'version': '1.4.1', 'ucs2': { 'decode': ucs2decode, 'encode': ucs2encode }, 'decode': decode, 'encode': encode, 'toASCII': toASCII, 'toUnicode': toUnicode }; if ( typeof define == 'function' && " & _
"typeof define.amd == 'object' && define.amd ) { define('punycode', function() { return punycode; }); } else if (freeExports && freeModule) { if (module.exports == freeExports) { freeModule.exports = punycode; } else { for (key in punycode) { punycode.hasOwnProperty(key) " & _
"&& (freeExports[key] = punycode[key]); } } } else { root.punycode = punycode; } }(this));"
End Function
Public Function IDNA2008_toPUNY(ByVal strINPUT As String)
ScriptEngine.AddCode IDNA2008_JScript
On Error Resume Next
IDNA2008_toPUNY = ScriptEngine.Eval("punycode.toASCII('" & strINPUT & "')")
On Error GoTo 0
Set moScriptEngine = Nothing
If IsEmpty(IDNA2008_toPUNY) Then IDNA2008_toPUNY = vbNullString
End Function
Public Function IDNA2008_toUNICODE(ByVal strINPUT As String)
ScriptEngine.AddCode IDNA2008_JScript
On Error Resume Next
IDNA2008_toUNICODE = ScriptEngine.Eval("punycode.toUnicode('" & strINPUT & "')")
On Error GoTo 0
Set moScriptEngine = Nothing
If IsEmpty(IDNA2008_toUNICODE) Then IDNA2008_toUNICODE = vbNullString
End Function
Sub TestPunyCode()
Debug.Print IDNA2008_toPUNY("schüloß.de")
Debug.Print IDNA2008_toUNICODE("xn--schlo-pqa4r.de")
End Sub
附加信息:
在 Windows 7 中使用 MS Office 2013(32 位)。
该解决方案无法尝试与 Unicode 域进行通信。如果可能的话,我不反对使用 WinHttp 对象,但出于安全原因,它不能发送或尝试将传出网络流量发送到域......
不幸的是,这是需要 VBA 解决方案而无需安装外部软件的问题之一。
再次,非常感谢任何帮助!