由於還是碼農新人,所以還未開始正式的編寫大的工程代碼,所以老員工給了我一個去年寫的大的PHP工程的工程代碼,先看下。抱著必須掃清每個死角的心裡,下午碰到了
shtmlspecialchars()函數,網上一查挺多人都在用的,但不是PHP自帶的,而是莫比較官方的寫的。但是這裡面的正則表達式著實讓我糾結了一方,不講廢話了,切入正題。
[php]
function shtmlspecialchars($string) {
if(is_array($string)) {
foreach($string as $key => $val) {
$string[$key] = shtmlspecialchars($val);
}
} else {
$string = preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/', '&\\1',
str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string));
}
return $string;
}
以上就是shtmlspecialchars()函數的定義,其他的不講,就講這句讓很多人揪心的
[php]
$string = preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/', '&\\1',
str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string));
這裡先介紹下這個函數的作用:
html中可能出現的四種特殊字符進行轉義,分別是
&轉&
"轉"
<轉<
>轉<(ps:這個後面的分號";"是連在一起的,一個整體,不是作者為了分隔用的)
這與PHP自帶的htmlspecialchars()效果剛好相反。
那麼一般人裡面會用下面的代碼實現這個函數所要實現的功能
[php]
str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string));
但是等一等!
問:等什麼?不是已經完成了這個功能了?
答:錯,大錯,特錯了,你這叫寧可枉殺3000,不放過一個,不人道的呀。
問:哪裡錯了?
答:情況下面的內容!
如果僅僅用上面的函數,那麼會將html特殊字符和unicode編碼都破壞掉這可不是我們要的結果,具體字符表見文章後面的附件。
有人觀察了字符表的所有數據,最後得出下面的結論:
1、html特殊字符都是由&#開頭後面加3-5個數字或者&#開頭加一個字符和2-5個字符或數字組成的字符串
2、unicode編碼是以&#開頭後面加4個16進制數字組成的字符串。
根據第一條,我們應該寫出正則表達式:&#/d{3,5}|[a-zA-Z][a-zA-Z0-9]{2,5};(ps:這個也是自帶分號";"的)
根據第二條,可以得出&#[a-fA-F0-9]{4}; (ps:因為16進制是從0-f)
又由於前面的操作已經把&替換成了&所以講上面兩條整合下就出了下面的
/&((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/
問題1:
有人問,是不是可以寫成下面的樣子
/&#(((\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/
把井號提出來,當然可以,不過如果你要這樣寫,後面的再提,有些下改動。
我們把第一步操作
[php]
str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string));
結果寫成$string
那麼反替換我們就可以簡略的寫成
preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/', '&\\1',$string)
這裡,前面的正則表達式已經很清楚了,但是作者又後面的&\\1搞暈了,什麼意思呀?
經查證\1代表正則表達式的第一個括號內的內容。
自己寫了一個測試
[php]
<?php
$string = 'x10p';
$string1 = preg_replace('/(x)([0-9]+)p/', '&\\1',$string);
$string2 = preg_replace('/x([0-9]+)p/', '&\\1',$string);
echo $string1;
echo '<br />';
echo $string2;
?>
輸出的結果分別是
&x 第一括號內的是 x
&10 第一括號內的是10
[php]
preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4})|[a-zA-Z][a-z0-9]{2,5});)/', '&\\1',$string)
結果就是僅僅把$amp;替換為&而後面的保留不變。
到這可以解決上面的問題1,是否可以把#拿出來,如果你吧#拿出來的話,那麼就是說會將&#都用&替換,然後後面的你得寫'&#\\1',這樣就可以,不過是不是感覺
多此一舉了?是的!
附錄:
html 字符表
特殊符號 命名實體 十進制編碼 特殊符號 命名實體 十進制編碼 特殊符號 命名實體 十進制編碼
Α Α Α Β Β Β Γ Γ Γ
Δ Δ Δ Ε Ε Ε Ζ Ζ Ζ
Η Η Η Θ Θ Θ Ι Ι Ι
Κ Κ Κ Λ Λ Λ Μ Μ Μ
Ν Ν Ν Ξ Ξ Ξ Ο Ο Ο
Π Π Π Ρ Ρ Ρ Σ Σ Σ
Τ Τ Τ Υ Υ Υ Φ Φ Φ
Χ Χ Χ Ψ Ψ Ψ Ω Ω Ω
α α α β β β γ γ γ
δ δ δ ε ε ε ζ ζ ζ
η η η θ θ θ ι ι ι
κ κ κ λ λ λ μ μ μ
ν ν ν ξ ξ ξ ο ο ο
π π π ρ ρ ρ ς ς ς
σ σ σ τ τ τ υ υ υ
φ φ φ χ χ χ ψ ψ ψ
ω ω ω ϑ ϑ ϑ ϒ ϒ ϒ
ϖ ϖ ϖ • • • … … …
′ ′ ′ ″ ″ ″ ‾ ‾ ‾
⁄ ⁄ ⁄ ℘ ℘ ℘ ℑ ℑ ℑ
ℜ ℜ ℜ ™ ™ ™ ℵ ℵ ℵ
← ← ← ↑ ↑ ↑ → → →
↓ ↓ ↓ ↔ ↔ ↔ ↵ ↵ ↵
⇐ ⇐ ⇐ ⇑ ⇑ ⇑ ⇒ ⇒ ⇒
⇓ ⇓ ⇓ ⇔ ⇔ ⇔ ∀ ∀ ∀
∂ ∂ ∂ ∃ ∃ ∃ ∅ ∅ ∅
∇ ∇ ∇ ∈ ∈ ∈ ∉ ∉ ∉
∋ ∋ ∋ ∏ ∏ ∏ ∑ ∑ −
− − − ∗ ∗ ∗ √ √ √
∝ ∝ ∝ ∞ ∞ ∞ ∠ ∠ ∠
∧ ∧ ⊥ ∨ ∨ ⊦ ∩ ∩ ∩
∪ ∪ ∪ ∫ ∫ ∫ ∴ ∴ ∴
∼ ∼ ∼ ≅ ≅ ≅ ≈ ≈ ≅
≠ ≠ ≠ ≡ ≡ ≡ ≤ ≤ ≤
≥ ≥ ≥ ⊂ ⊂ ⊂ ⊃ ⊃ ⊃
⊄ ⊄ ⊄ ⊆ ⊆ ⊆ ⊇ ⊇ ⊇
⊕ ⊕ ⊕ ⊗ ⊗ ⊗ ⊥ ⊥ ⊥
⋅ ⋅ ⋅ ⌈ ⌈ ⌈ ⌉ ⌉ ⌉
⌊ ⌊ ⌊ ⌋ ⌋ ⌋ ◊ ◊ ◊
♠ ♠ ♠ ♣ ♣ ♣ ♥ ♥ ♥
♦ ♦ ♦   ¡ ¡ ¡
¢ ¢ ¢ £ £ £ ¤ ¤ ¤
¥ ¥ ¥ ¦ ¦ ¦ § § §
¨ ¨ ¨ © © © ª ª ª
« « « ¬ ¬ ¬ ­ ­
® ® ® ¯ ¯ ¯ ° ° °
± ± ± ² ² ² ³ ³ ³
´ ´ ´ µ µ µ " " "
< < < > > > ' '