頭痛的ASCII和preg_replace()

huidaoli發表於2013-07-29

說這個之前,大家先看下這條語句:

preg_replace("/\<\?\=(\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\[\]\"\'\$\x7f-\xff]*)\?\>/s", "\\1", $p2));

此例是應用preg_replace()函式,當你第一 次看時,是不是有如下幾點疑問:
1.\<\?\=,不理解為何要用上轉義符號\,看了語法教程,正則中並沒有這樣的寫法,只有\s、\d、\w等七種,而且雙引號中包含字串也不需要用到轉義字元啊(指\ ? =這三種),不明白為何要用上轉義字元?
2.\\\$,這點如何理解?是匹配反斜槓和$這個定位字元($表示匹配的模式出現在匹配物件的末尾),還是理解為\\和\$(這個表示$字元)?個人理解是匹配\\和\$,假如我的理解是正確的,那\\\$這第一個反斜槓是何作用(後面的\\$則是匹配$,代表變數名)?
3.\x7f-\xff,這是匹配ASCII擴充套件碼的,我測試一下下面的程式碼:

1 <?
2 $str="ǎ";
3 print preg_replace("/\x7f-\xff/","erw",$str);
4 ?>
View Code

但執行結果是隻輸出ǎ,不匹配,但我檢視了ASCII擴充套件碼,ǎ是屬於擴充套件碼的呀,為何不匹配呢?是不是我哪裡寫錯了?還有,PHP變數名命名規則中規定變數名不能取副檔名中的任何一個字元啊,但上面的\\\$[a-zA-Z_\x7f-\xff如果是匹配變數名的話,這\x7f-\xff又有何作用呢?變數名不允許取自這些字元,用上沒有意義啊?
4.

$template = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}/s", "<?=\\1".PHP_CLOSE_TAG, $template);

你不會說這句好象是匹配變數名稱的,呵呵,但此例的\[\]又是匹配什麼,是不是看了半天也沒明白,另外\'\"是匹配單引號和雙引號的,\$\x7f-\xff是匹配ASCII擴充套件碼的,但單引號及雙引號還有ASCII擴充套件碼並不能用於變數命名呀,為何要寫上這樣的匹配條件,是不是有點不解啊。還有,大括號用來精確指定匹配元字元出現的次數(語法資料上是這樣寫的),但是你有沒有發現上面的大括號好像並不是這個作用呀,那用上大括號是何作用呢?

先別急,在解答之前,先讓大家看一下熟悉的ASCII碼及其擴充套件碼。

ASCII 碼使用指定的7 位或8 位二進位制數組合來表示128 或256 種可能的字元。標準ASCII 碼也叫基礎ASCII碼,使用7 位二進位制數來表示所有的大寫和小寫字母,數字0 到9、標點符號, 以及在美式英語中使用的特殊控制字元。其中:
0~31及127(共33個)是控制字元或通訊專用字元(其餘為可顯示字元),如控制符:LF(換行)、CR(回車)、FF(換頁)、DEL(刪除)、BS(退格)、BEL(響鈴)等;通訊專用字元:SOH(文頭)、EOT(文尾)、ACK(確認)等;ASCII值為8、9、10 和13 分別轉換為退格、製表、換行和回車字元。它們並沒有特定的圖形顯示,但會依不同的應用程式,而對文字顯示有不同的影響。
32~126(共95個)是字元(32sp是空格),其中48~57為0到9十個阿拉伯數字
65~90為26個大寫英文字母,97~122號為26個小寫英文字母,其餘為一些標點符號、運算子號等。
同時還要注意,在標準ASCII中,其最高位(b7)用作奇偶校驗位。所謂奇偶校驗,是指在程式碼傳送過程中用來檢驗是否出現錯誤的一種方法,一般分奇校驗和偶校驗兩種。奇校驗規定:正確的程式碼一個位元組中1的個數必須是奇數,若非奇數,則在最高位b7添1;偶校驗規定:正確的程式碼一個位元組中1的個數必須是偶數,若非偶數,則在最高位b7添1。
後128個稱為擴充套件ASCII碼,目前許多基於x86的系統都支援使用擴充套件(或“高”)ASCII。擴充套件ASCII 碼允許將每個字元的第8 位用於確定附加的128 個特殊符號字元、外來語字母和圖形符號。

標準ASCII表

Bin
Dec
Hex
縮寫/字元
解釋
0000 0000
0
00
NUL(null)
空字元
0000 0001
1
01
SOH(start of headline)
標題開始
0000 0010
2
02
STX (start of text)
正文開始
0000 0011
3
03
ETX (end of text)
正文結束
0000 0100
4
04
EOT (end of transmission)
傳輸結束
0000 0101
5
05
ENQ (enquiry)
請求
0000 0110
6
06
ACK (acknowledge)
收到通知
0000 0111
7
07
BEL (bell)
響鈴
0000 1000
8
08
BS (backspace)
退格
0000 1001
9
09
HT (horizontal tab)
水平製表符
0000 1010
10
0A
LF (NL line feed, new line)
換行鍵
0000 1011
11
0B
VT (vertical tab)
垂直製表符
0000 1100
12
0C
FF (NP form feed, new page)
換頁鍵
0000 1101
13
0D
CR (carriage return)
Enter鍵
0000 1110
14
0E
SO (shift out)
不用切換
0000 1111
15
0F
SI (shift in)
啟用切換
0001 0000
16
10
DLE (data link escape)
資料鏈路轉義
0001 0001
17
11
DC1 (device control 1)
裝置控制1
0001 0010
18
12
DC2 (device control 2)
裝置控制2
0001 0011
19
13
DC3 (device control 3)
裝置控制3
0001 0100
20
14
DC4 (device control 4)
裝置控制4
0001 0101
21
15
NAK (negative acknowledge)
拒絕接收
0001 0110
22
16
SYN (synchronous idle)
同步空閒
0001 0111
23
17
ETB (end of trans. block)
傳輸塊結束
0001 1000
24
18
CAN (cancel)
取消
0001 1001
25
19
EM (end of medium)
介質中斷
0001 1010
26
1A
SUB (substitute)
替補
0001 1011
27
1B
ESC (escape)
換碼(溢位)
0001 1100
28
1C
FS (file separator)
檔案分割符
0001 1101
29
1D
GS (group separator)
分組符
0001 1110
30
1E
RS (record separator)
記錄分離符
0001 1111
31
1F
US (unit separator)
單元分隔符
0010 0000
32
20
(space)
空格
0010 0001
33
21
!
 
0010 0010
34
22
"
 
0010 0011
35
23
#
 
0010 0100
36
24
$
 
0010 0101
37
25
%
 
0010 0110
38
26
&
 
0010 0111
39
27
'
 
0010 1000
40
28
(
 
0010 1001
41
29
)
 
0010 1010
42
2A
*
 
0010 1011
43
2B
+
 
0010 1100
44
2C
,
 
0010 1101
45
2D
-
 
0010 1110
46
2E
.
 
00101111
47
2F
/
 
00110000
48
30
0
 
00110001
49
31
1
   
00110010
50
32
2
   
00110011
51
33
3
   
00110100
52
34
4
   
00110101
53
35
5
   
00110110
54
36
6
   
00110111
55
37
7
   
00111000
56
38
8
   
00111001
57
39
9
   
00111010
58
3A
:
   
00111011
59
3B
;
   
00111100
60
3C
<
   
00111101
61
3D
=
   
00111110
62
3E
>
   
00111111
63
3F
?
   
01000000
64
40
@
   
01000001
65
41
A
   
01000010
66
42
B
   
01000011
67
43
C
   
01000100
68
44
D
   
01000101
69
45
E
   
01000110
70
46
F
   
01000111
71
47
G
   
01001000
72
48
H
   
01001001
73
49
I
   
01001010
74
4A
J
   
01001011
75
4B
K
   
01001100
76
4C
L
   
01001101
77
4D
M
   
01001110
78
4E
N
   
01001111
79
4F
O
   
01010000
80
50
P
   
01010001
81
51
Q
   
01010010
82
52
R
   
01010011
83
53
S
   
01010100
84
54
T
   
01010101
85
55
U
   
01010110
86
56
V
   
01010111
87
57
W
   
01011000
88
58
X
   
01011001
89
59
Y
   
01011010
90
5A
Z
   
01011011
91
5B
[
   
01011100
92
5C
\
   
01011101
93
5D
]
   
01011110
94
5E
^
   
01011111
95
5F
_
   
01100000
96
60
`
   
01100001
97
61
a
   
01100010
98
62
b
   
01100011
99
63
c
   
01100100
100
64
d
   
01100101
101
65
e
   
01100110
102
66
f
   
01100111
103
67
g
   
01101000
104
68
h
   
01101001
105
69
i
   
01101010
106
6A
j
   
01101011
107
6B
k
   
01101100
108
6C
l
   
01101101
109
6D
m
   
01101110
110
6E
n
   
01101111
111
6F
o
   
01110000
112
70
p
   
01110001
113
71
q
   
01110010
114
72
r
   
01110011
115
73
s
   
01110100
116
74
t
   
01110101
117
75
u
   
01110110
118
76
v
   
01110111
119
77
w
   
01111000
120
78
x
   
01111001
121
79
y
   
01111010
122
7A
z
   
01111011
123
7B
{
   
01111100
124
7C
|
   
01111101
125
7D
}
   
01111110
126
7E
~
   
01111111
127
7F
DEL (delete)
刪除
 
八進位制
十六進位制
十進位制
字元
八進位制
十六進位制
十進位制
字元
0
0
0
nul
100
40
64
@
1
1
1
soh
101
41
65
A
2
2
2
stx
102
42
66
B
3
3
3
etx
103
43
67
C
4
4
4
eot
104
44
68
D
5
5
5
enq
105
45
69
E
6
6
6
ack
106
46
70
F
7
7
7
bel
107
47
71
G
10
8
8
bs
110
48
72
H
11
9
9
ht
111
49
73
I
12
0a
10
nl
112
4a
74
J
13
0b
11
vt
113
4b
75
K
14
0c
12
ff
114
4c
76
L
15
0d
13
er
115
4d
77
M
16
0e
14
so
116
4e
78
N
17
0f
15
si
117
4f
79
O
20
10
16
dle
120
50
80
P
21
11
17
dc1
121
51
81
Q
22
12
18
dc2
122
52
82
R
23
13
19
dc3
123
53
83
S
24
14
20
dc4
124
54
84
T
25
15
21
nak
125
55
85
U
26
16
22
syn
126
56
86
V
27
17
23
etb
127
57
87
W
30
18
24
can
130
58
88
X
31
19
25
em
131
59
89
Y
32
1a
26
sub
132
5a
90
Z
33
1b
27
esc
133
5b
91
[
34
1c
28
fs
134
5c
92
\
35
1d
29
gs
135
5d
93
]
36
1e
30
re
136
5e
94
^
37
1f
31
us
137
5f
95
_
40
20
32
sp
140
60
96
'
41
21
33
!
141
61
97
a
42
22
34
"
142
62
98
b
43
23
35
#
143
63
99
c
44
24
36
$
144
64
100
d
45
25
37
%
145
65
101
e
46
26
38
&
146
66
102
f
47
27
39
`
147
67
103
g
50
28
40
(
150
68
104
h
51
29
41
)
151
69
105
i
52
2a
42
*
152
6a
106
j
53
2b
43
+
153
6b
107
k
54
2c
44
,
154
6c
108
l
55
2d
45
-
155
6d
109
m
56
2e
46
.
156
6e
110
n
57
2f
47
/
157
6f
111
o
60
30
48
0
160
70
112
p
61
31
49
1
161
71
113
q
62
32
50
2
162
72
114
r
63
33
51
3
163
73
115
s
64
34
52
4
164
74
116
t
65
35
53
5
165
75
117
u
66
36
54
6
166
76
118
v
67
37
55
7
167
77
119
w
70
38
56
8
170
78
120
x
71
39
57
9
171
79
121
y
72
3a
58
:
172
7a
122
z
73
3b
59
;
173
7b
123
{
74
3c
60
<
174
7c
124
|
75
3d
61
=
175
7d
125
}
76
3e
62
>
176
7e
126
~
77
3f
63
?
177
7f
127
del

常見ASCII碼的大小規則

1)數字0~9比字母要小。如"7"<"F";
2)數字0比數字9要小,並按0到9順序遞增。如"3"<"8"
3)字母A比字母Z要小,並按A到Z順序遞增。如"A"<"Z"
4)同個字母的大寫字母比小寫字母要小。如"A"<"a"。
記住幾個常見字母的ASCII碼大小:
“換行LF”為0x0A;“回車CR”為0x0D;空格為0x20;"0"為0x30; "A"為0x41;"a"為0x61。
另外還有128-255的ASCII字元查詢ASCII技巧方便查詢ASCII碼對應的字元:新建一個文字文件,按住ALT+要查詢的碼值(注意,這裡是十進位制)
鬆開即可顯示出對應字元。例如:按住ALT+97,則會顯示出‘a'。

虛擬鍵盤按鍵的ASCII值

ESC鍵VK_ESCAPE (27)
Enter鍵:VK_RETURN (13)
TAB鍵:VK_TAB (9)
Caps Lock鍵:VK_CAPITAL (20)
Shift鍵:VK_SHIFT (16)
Ctrl鍵:VK_CONTROL (17)
Alt鍵:VK_MENU (18)
空格鍵:VK_SPACE (32)
退格鍵:VK_BACK (8)
左徽標鍵:VK_LWIN (91)
右徽標鍵:VK_RWIN (92)
滑鼠右鍵快捷鍵:VK_APPS (93)
Insert鍵:VK_INSERT (45)
Home鍵:VK_HOME (36)
Page Up:VK_PRIOR (33)
PageDown:VK_NEXT (34)
End鍵:VK_END (35)
Delete鍵:VK_DELETE (46)
方向鍵(←):VK_LEFT (37)
方向鍵(↑):VK_UP (38)
方向鍵(→):VK_RIGHT (39)
方向鍵(↓):VK_DOWN (40)
F1鍵:VK_F1 (112)
F2鍵:VK_F2 (113)
F3鍵:VK_F3 (114)
F4鍵:VK_F4 (115)
F5鍵:VK_F5 (116)
F6鍵:VK_F6 (117)
F7鍵:VK_F7 (118)
F8鍵:VK_F8 (119)
F9鍵:VK_F9 (120)
F10鍵:VK_F10 (121)
F11鍵:VK_F11 (122)
F12鍵:VK_F12 (123)
Num Lock鍵:VK_NUMLOCK (144)
小鍵盤0:VK_NUMPAD0 (96)
小鍵盤1:VK_NUMPAD1 (97)
小鍵盤2:VK_NUMPAD2 (98)
小鍵盤3:VK_NUMPAD3 (99)
小鍵盤4:VK_NUMPAD4 (100)
小鍵盤5:VK_NUMPAD5 (101)
小鍵盤6:VK_NUMPAD6 (102)
小鍵盤7:VK_NUMPAD7 (103)
小鍵盤8:VK_NUMPAD8 (104)
小鍵盤9:VK_NUMPAD9 (105)
小鍵盤。:VK_DECIMAL (110)
小鍵盤*:VK_MULTIPLY (106)
小鍵盤+:VK_ADD (107)
小鍵盤-:VK_SUBTRACT (109)
小鍵盤/:VK_DIVIDE (111)
Pause Break鍵:VK_PAUSE (19)
Scroll Lock鍵:VK_SCROLL (145)

本文寫到這,還真是見笑了,正則真的很複雜(對新手來說),好多地方都不明白,讓人頭都搞大,當然本人水平有限,還希望能得到高手們的指點.

 正則是個好東西,又是個壞東西.她好如仙女,讓你做神仙眷侶;壞如魔鬼,讓你生不如死.沒有什麼特別的書能夠說講得好,但是最基本的PERC的又是最基礎講得最好的.
一切需要悟性,用,則學一輩子,也許終此一生門外徘徊,但是不要氣餒,至少你學過了.不用,則當機立斷,終老一生時,你會慶幸當初沒有學,否則一輩子的光陰白白耗費在幾個變來換去的字元上! 

其實上面的/\x7f-\xff/表示三個字元,而/[\x7f-\xff]/才表示一個範圍之內的字元,繼續往下寫,

我們寫一段程式碼測試下:

<?
$str="ǎ";
print preg_replace("/[\x7f-\xff]/","erw",$str);
?>

呵呵,看到了吧,總算有字元輸出了,執行結果如下:
erwerw
是不是很奇怪啊,只有一個ǎ啊,為何有兩次替換的動作呢?另外,/\x7f-\xff/表示三個字元,這是哪三個字元呢?你想半天也不會明白是怎麼回事,還是繼續向下看吧。
看來還是得修改下程式碼:

<?
$str="ǎ";
print preg_replace("/[\x7f-\xff]{2}/","erw",$str);
?>

OK,執行結果:
ǎ
這下總算輸出預期結果了,但為何非要加上{2}才會輸出這個結果呢?這大括號用來精確指定匹配元字元出現的次數,上面的[\x7f-\xff]同[z-z]不也一樣的嗎?只要匹配其中的一個即可完成替換動作,ǎ也符合這個條件啊,但事實是不加上{2}就不會輸出一個ǎ這個結果,想了半天,大家是不是還是不解,讓我再教教你們吧!

我再舉一個例子:

<?
$str="a";
print preg_replace("/[a-z]/","1",$str);
?>

執行結果:
1
看,只會替換一次的,那我上面的例子又是怎麼回事呢 ...

這是因為127以下的字元是7bit,擴充套件字元是8bit,這7bit和8bit對於preg_replace()函式是有影響的?

還有下面的一個例子:

$str = "超越PHP";
if  (preg_match("/^[".chr(0xa1)."-".chr(0xff)."]+$/", $str)) {
    echo "這是一個純中文字串";
} else {
    echo "這不是一個純中文字串";
}

是不是搞不懂0xa1、0xff這些進位制是如何轉換的呢?

漢字是雙位元組的下面摘自php中文手冊:

注: 單引號或雙引號括起來的 PHP 字串中的反斜線有特殊含義。因此必須用正規表示式的 \\ 來匹配 \,而在 PHP 程式碼中要用 "\\\\" 或 '\\\\'。

單引號或雙引號括起來的 PHP 字串中的反斜線有特殊含義。因此必須用正規表示式的 \\ 來匹配 \,我用如下程式碼測試:

<?
$str="\";

print preg_replace("/\\/","5",$str);
?>

什麼也沒有輸出,顯然並沒有匹配條件,再修改如下:

<?
$str="\";

print preg_replace("/\\\/","5",$str);
?>

是沒有任何輸出,最後修改如下:

<?
$str="\\";

print preg_replace("/\\\/","5",$str);
?>

算OK了,輸出5,條件匹配了

但對照上面所說的匹配條件(單引號或雙引號括起來的 PHP 字串中的反斜線有特殊含義。因此必須用正規表示式的 \\ 來匹配 \),兩者是不是感覺有點不對應啊,字串中如果帶有反斜槓必須要用\\才能輸出(一個反斜槓不會有任何輸出的),那正則中必須要以轉義字元\再加兩個反斜槓才能匹配反斜槓啊,我最後的示例就是這樣,但按照手冊所說的須用正規表示式的 \\ 來匹配 \,無法成功匹配啊,是不是還是沒有徹底明白,按上面的說法\\\$的確是匹配一個反斜槓和一個$符號(\\匹配一個反斜槓,\$匹配$符號),我們再測試了一下如下程式碼:

<?
$str="\\\$";

print preg_replace("/\\\$/","5",$str);
?>

輸出\5,但怎麼都不能理解正規表示式的 \\ 來匹配 \這點,哪裡理解出錯了呢。

接下來的[\]依上面是對應[, ],但測試如下程式碼無論如何都不能通過:

<?
$str=",";

print preg_replace("/[\]/","5",$str);
?>

只有將[\]改為[,]才會匹配條件。

最後,\x7f-\xff是匹配127-255的ascii碼,上面的工作上已測試瞭如下程式碼:

<?
$str="ǎ";
print preg_replace("/[\x7f-\xff]{2}/","erw",$str);
?>

執行一切正常,但必須要加上{2}這個條件才行,同時我已經說過127以下的字元是7bit,擴充套件字元是8bit,那這位元組數不一樣,對於preg_replace()函式的執行具體影響在哪兒?

這主要是 因為在字串之中,\本來就會轉義的.關鍵時刻看下手冊:

ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/

好了,今天就說到這了,下次有時間再說,還望大家多多指教啊。有問題請在下面說就可以了。

 

 

相關文章