如何将.NET中[Url(UrlOptions.DisallowProtocol)]的URL正则转为JS正则?
[Url(UrlOptions.DisallowProtocol)] Regex to JavaScript Got it, I totally get the pain of dealing with that super long regex from .NET's Url attribute—converting it to JavaScript without breaking things can feel like untangling a knot. Let's break down the steps and tools (no external links needed!) to get this done smoothly.
First, Understand the Key Differences
The main hurdles here are:
- HTML Entities: The original regex has
&instead of plain&(that's an HTML escape leftover from wherever you copied it from). - Escape Characters: .NET uses double backslashes (
\\) in string literals for regex escapes, but JavaScript handles this differently depending on whether you use a regex literal (/.../) or theRegExpconstructor. - Unicode Support: Both .NET and modern JS support Unicode ranges like
\u00A0-\uD7FF, so that part is mostly compatible.
Step-by-Step Conversion Method
1. Fix HTML Entities First
Replace every instance of & in the original regex string with &. This is non-negotiable—JS regex doesn't recognize HTML entities, so this will break matches for characters like & if you skip it.
2. Handle Escape Characters
You have two options here, depending on how you want to define your JS regex:
Option A: Use a Regex Literal (Recommended)
Regex literals (/pattern/) don't require double escaping backslashes, so you can replace all \\ in the .NET string with a single \. This makes the regex much cleaner and easier to read.
Here's the converted regex literal ready to use in JS:
const urlRegex = /^((https?|ftp):\/\/)?(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!$&'()*+,;=]|:)*@)?(((|\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|([a-zA-Z][\-a-zA-Z0-9]*)|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!$&'()*+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!$&'()*+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!$&'()*+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!$&'()*+,;=]|:|@)|\/|\?)*)?$/;
Option B: Use the RegExp Constructor
If you need to build the regex dynamically, keep the double backslashes but replace & with &. Here's how to do it with a quick script:
// Original .NET regex string const dotNetRegexStr = '^((https?|ftp):\\/\\/)?(((([a-zA-Z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-fA-F]{2})|[!\\$&\\'(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|([a-zA-Z][\\-a-zA-Z0-9]*)|((([a-zA-Z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-zA-Z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-zA-Z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-zA-Z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))\\.)+(([a-zA-Z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-zA-Z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-zA-Z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-zA-Z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))\\.?)(:\\d*)?)(\\/((([a-zA-Z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-fA-F]{2})|[!\\$&\\'(\\)\\*\\+,;=]|:|@)+(\\/(([a-zA-Z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-fA-F]{2})|[!\\$&\\'(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-zA-Z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-fA-F]{2})|[!\\$&\\'(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-zA-Z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-fA-F]{2})|[!\\$&\\'(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$'; // Step 1: Replace HTML entities let jsRegexStr = dotNetRegexStr.replace(/&/g, '&'); // Step 2: Create the regex (no need to change backslashes here) const urlRegex = new RegExp(jsRegexStr);
3. Test the Regex
Always verify that the converted regex behaves the same as the .NET version. Here are some test cases to run in your browser console or Node.js REPL:
// Should all return true console.log(urlRegex.test("example.com")); console.log(urlRegex.test("https://example.com/path?query=value#hash")); console.log(urlRegex.test("ftp://user@ftp.example.org:21/file.txt")); console.log(urlRegex.test("sub.domain.co.uk"));
Quick Script for Batch Conversion
If you ever need to do this again, you can write a tiny JS function to handle the conversion automatically:
function convertDotNetRegexToJS(dotNetRegex) { // Replace HTML entities let jsRegex = dotNetRegex.replace(/&/g, '&'); // Convert to literal-friendly (remove double backslashes) jsRegex = jsRegex.replace(/\\\\/g, '\\'); return new RegExp(jsRegex); } // Usage const myUrlRegex = convertDotNetRegexToJS(dotNetRegexStr);
Key Notes
- Unicode Support: Make sure your JS environment supports ES6+ Unicode regex (all modern browsers and Node.js 6+ do).
- Edge Cases: Test edge URLs (like those with Unicode characters, special symbols in paths, or non-standard ports) to ensure parity with .NET's validation.
内容的提问来源于stack exchange,提问作者Misha Zaslavsky

