Regex để thực hiện phân tích cú pháp đầy đủ là khá khủng khiếp. Tôi đã bao gồm các phản hồi có tên về mức độ dễ đọc và chia từng phần thành các dòng riêng biệt, nhưng nó vẫn trông như thế này:
^(?:(?P<protocol>\w+(?=:\/\/))(?::\/\/))?
(?:(?P<host>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^\/?#:]+)(?::(?P<port>[0-9]+))?)\/)?
(?:(?P<path>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)\/)?
(?P<file>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)
(?:\?(?P<querystring>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^#])+))?
(?:#(?P<fragment>.*))?$
Điều đòi hỏi nó phải thật dài dòng là ngoại trừ giao thức hoặc cổng, bất kỳ phần nào cũng có thể chứa các thực thể HTML, khiến cho việc phân định đoạn này khá khó khăn. Vì vậy, trong một vài trường hợp gần đây - máy chủ, đường dẫn, tệp, chuỗi truy vấn và đoạn, chúng tôi cho phép bất kỳ thực thể html hoặc bất kỳ ký tự nào không phải là ?
hoặc #
. Regex cho một thực thể html trông như thế này:
$htmlentity = "&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);"
Khi được trích xuất (tôi đã sử dụng cú pháp ria mép để thể hiện nó), nó trở nên dễ đọc hơn một chút:
^(?:(?P<protocol>(?:ht|f)tps?|\w+(?=:\/\/))(?::\/\/))?
(?:(?P<host>(?:{{htmlentity}}|[^\/?#:])+(?::(?P<port>[0-9]+))?)\/)?
(?:(?P<path>(?:{{htmlentity}}|[^?#])+)\/)?
(?P<file>(?:{{htmlentity}}|[^?#])+)
(?:\?(?P<querystring>(?:{{htmlentity}};|[^#])+))?
(?:#(?P<fragment>.*))?$
Tất nhiên, trong JavaScript, bạn không thể sử dụng các phản hồi có tên, do đó regex trở thành
^(?:(\w+(?=:\/\/))(?::\/\/))?(?:((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^\/?#:]+)(?::([0-9]+))?)\/)?(?:((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)\/)?((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)(?:\?((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^#])+))?(?:#(.*))?$
và trong mỗi trận đấu, giao thức là \1
, máy chủ lưu trữ \2
, cổng là \3
, đường dẫn \4
, tệp \5
, chuỗi truy vấn \6
và đoạn \7
.
CrackUrl
. Nếu một chức năng như vậy tồn tại, sử dụng nó, nó gần như được đảm bảo là đáng tin cậy và hiệu quả hơn bất kỳ mã thủ công nào.