2015-11-05 77 views
0

我问过一个以前在这里的问题,但决定应该把问题分解成多个问题(这有助于我进一步调试!找出我需要更多的到底是什么)删除多个尾随连字符PHP正则表达式(不包括在“。”中的字符???)

对这里的另一个用户提供了一个相当不错的正则表达式关键检测和超链接的URL,它被分解到下面的以下几个部分:

$rexProtocol = '(https?://)?'; 
$rexDomain = '((?:[-a-zA-Z0-9]{1,63}\.)+[-a-zA-Z0-9]{2,63}|(?:[0-9]{1,3}\.){3}[0-9]{1,3})'; 
$rexPort  = '(:[0-9]{1,5})?'; 
$rexPath  = '(/[!$-/0-9:;[email protected]_\':;!a-zA-Z\x7f-\xff]*?)?'; 
$rexQuery = '(\?[!$-/0-9:;[email protected]_\':;!a-zA-Z\x7f-\xff]+?)?'; 
$rexFragment = '(#[!$-/0-9:;[email protected]_\':;!a-zA-Z\x7f-\xff]+?)?'; 

这是一个很好的方式来打破我的URL,虽然这当然是来自一个正在努力更熟悉REGEX引擎世界的人。许多优秀的情况下,将与此同时,有条件的被抓:

while (preg_match("{\\b$rexProtocol$rexDomain$rexPort$rexPath$rexQuery$rexFragment(?=[?.!,;:\"]?(\s|$))}", $text, &$match, PREG_OFFSET_CAPTURE, $position)) {... 

一件事,我发现这种略带沮丧的,但问题在于,这并不完全捕获的链接,同时留出尾随标点符号和其他字符(它只在链接末尾使用一个标点符号等)。因此,我决定更动条件和一些调整和研究后,发现了以下条件的工作太多更好 - /s被替换为.代替:

while (preg_match("{\\b$rexProtocol$rexDomain$rexPort$rexPath$rexQuery$rexFragment(?=[?.!,;:\"\'-]?(.|$))}", $text, $match, PREG_OFFSET_CAPTURE, $position)) 

这实际上涵盖了大多数非字母数字字符结尾在一个句子的URL末尾。你会认为这将包括连字符,但由于某种原因,它不仅仅从URL的末尾删除一个连字符并将剩余的连字符排除,THUS阻止我通过多于一个连字符。任何建议可能会更改REGEX键或代码中的其他内容?下面是我下面的修改后的代码的其余部分:

function formatTextLinksVerbose($text) { 
    $rexProtocol = '(https?://)?'; 
    $rexDomain = '((?:[-a-zA-Z0-9]{1,63}\.)+[-a-zA-Z0-9]{2,63}|(?:[0-9]{1,3}\.){3}[0-9]{1,3})'; 
    $rexPort  = '(:[0-9]{1,5})?'; 
    $rexPath  = '(/[!$-/0-9:;[email protected]_\':;!a-zA-Z\x7f-\xff]*?)?'; 
    $rexQuery = '(\?[!$-/0-9:;[email protected]_\':;!a-zA-Z\x7f-\xff]+?)?'; 
    $rexFragment = '(#[!$-/0-9:;[email protected]_\':;!a-zA-Z\x7f-\xff]+?)?'; 

    $validTlds = array_fill_keys(explode(" ", ".aero .asia .biz .cat .com .coop .edu .gov .info .int .jobs .mil .mobi .museum .name .net .org .pro .tel .travel .ac .ad .ae .af .ag .ai .al .am .an .ao .aq .ar .as .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .cr .cu .cv .cx .cy .cz .de .dj .dk .dm .do .dz .ec .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .io .iq .ir .is .it .je .jm .jo .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mk .ml .mm .mn .mo .mp .mq .mr .ms .mt .mu .mv .mw .mx .my .mz .na .nc .ne .nf .ng .ni .nl .no .np .nr .nu .nz .om .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .ps .pt .pw .py .qa .re .ro .rs .ru .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .ye .yt .yu .za .zm .zw .xn--0zwm56d .xn--11b5bs3a9aj6g .xn--80akhbyknj4f .xn--9t4b11yi5a .xn--deba0ad .xn--g6w251d .xn--hgbk6aj7f53bba .xn--hlcj6aya9esc7a .xn--jxalpdlp .xn--kgbechtv .xn--zckzah .arpa"), true); 

    $position = 0; 
    $returnText = ""; 
    while (preg_match("{\\b$rexProtocol$rexDomain$rexPort$rexPath$rexQuery$rexFragment(?=[?.!,;:\"]?(.|$))}", $text, $match, PREG_OFFSET_CAPTURE, $position)) 
    { 
     list($url, $urlPosition) = $match[0]; 

     // Append the text leading up to the URL in return value. 
     $returnText .= htmlspecialchars(substr($text, $position, $urlPosition - $position)); 

     $domain = $match[2][0]; 
     $port = $match[3][0]; 
     $path = $match[4][0]; 

     // Check if the TLD is valid - or that $domain is an IP address. 
     $tld = strtolower(strrchr($domain, '.')); 
     if (preg_match('{\.[0-9]{1,3}}', $tld) || isset($validTlds[$tld])) 
     { 
      // Prepend http:// if no protocol specified 
      $completeUrl = $match[1][0] ? $url : "http://$url"; 

      // Append the hyperlink. 
      $returnText .= '<a href="' . htmlspecialchars($completeUrl) . '">' . htmlspecialchars("$domain$port$path") . '</a>'; 
     } 
     else 
     { 
      // Not a valid URL. 
      $returnText .= htmlspecialchars($url); 
     } 

     // Continue text parsing from after the URL. 
     $position = $urlPosition + strlen($url); 
    } 

    // Append and return the remainder of the text. 
    return($returnText . htmlspecialchars(substr($text, $position))); 
} 

(在一个侧面说明,我认识到,用htmlspecialchars应该从我的形式提交到这个页面用户的不当行为,以保护,但有在该功能的地方我可以放弃担心这个问题了吗?我应该解密回非函数的非HTML字符串吗?看到输出包含双引号作为'& qout'字符代码)

+0

你指的文本包含“””一个网址后立即?我看不出你如何能确定这是否是URL的一部分或没有。我会建议寻找一个空白字符来表示一个url的结尾 – Phil

+0

我认为这个关键是这样布置的,这样你就可以在结束的TLD之后过滤非字母数字字符,这个过滤器就是这样,我得到了这个函数来工作“www.stackoverflow .com ...,“”www。“。”和“www.stackoverflow.com ___”。每个标点符号字符的情况下,但连字符的作品。我不知道为什么。我注意到它会筛选多个连字符时,我指定它之前(。| $)显然,但我不能使用“+”或“*”。 –

+0

确实,当使用“内部url”时,浏览器会在实际请求发生时将其转移到%22。这并不意味着它必须在通用文本中逃脱。实际上,大多数浏览器都会在url栏中显示非转义字符以提高可见性。你为什么把网址放在引号中? – Phil

回答

0

不是答案你的问题。只是一般的观察。
你可以分解出一些正则表达式的部分,并使用命名捕捉组
这样你就不必重做代码体,当你改变/修改
正则表达式。

$prot = '(?<Protocol>https?://)?'; 
$domain = '(?<Domain>(?:(?&lt){1,63}\.)+(?&lt){2,63}|(?:[0-9]{1,3}\.){3}[0-9]{1,3})'; 
$port = '(?<Port>:[0-9]{1,5})?'; 
$other = '(?<Path>/(?&txt)*?)?(?<Query>\?(?&txt)+?)?(?<Fragment>\#(?&txt)+?)?'; 
$def = '(?(DEFINE)(?<lt>[-a-zA-Z0-9])(?<txt>[!$-/0-9:;[email protected]_\'a-zA-Z\x7f-\xff]))'; 

$regex = "$prot$domain$port$other$def"; 

while (preg_match("{\\b$regex(?=[?.!,;:\"]?(.|$))}", $text, $match, PREG_OFFSET_CAPTURE, $position)) 
{ 

} 

或者,如果你愿意,格式化,正则表达式,并使用忽略空格标志//x

这样做可以让您在表达式中看到变量名称。
以后可以避免混淆。这样做的好工具是here

while (
    preg_match(
    '~ 
     (?<Protocol> https?://)?  # (1) 
     (?<Domain>     # (2) 
      (?: 
        (?&lt){1,63} \. 
      )+ 
      (?&lt){2,63} 
      | (?: [0-9]{1,3} \.){3} 
      [0-9]{1,3} 
     ) 
     (?<Port> : [0-9]{1,5})?  # (3) 
     (?<Path>      # (4) 
      /(?&txt)*? 
     )? 
     (?<Query>      # (5) 
      \? (?&txt)+? 
     )? 
     (?<Fragment>     # (6) 
      \# (?&txt)+? 
     )? 
     (?(DEFINE) 
      (?<lt> [-a-zA-Z0-9])   # (7) 
      (?<txt>      # (8) 
        [!$-/0-9:;[email protected]_\'a-zA-Z\x7f-\xff] 
      ) 
     ) 
     (?=[?.!,;:"]?(.|$)) 
    ~x' 
    , $text, $match, PREG_OFFSET_CAPTURE, $position)) 
{ 

} 
+0

这一点非常感谢......谢谢! –

相关问题