头痛的ASCII和preg_replace()

时间:2023-12-28 10:59:02

说这个之前,大家先看下这条语句:

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扩展码的,我测试一下下面的代码:

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

但运行结果是只输出ǎ,不匹配,但我查看了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
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)
回车键
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
 
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)
删除
 
八进制
十六进制
十进制
字符
八进制
十六进制
十进制
字符
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
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和preg_replace()

常见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和preg_replace()

虚拟键盘按键的ASCII值

ESC键VK_ESCAPE (27)
回车键: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/

好了,今天就说到这了,下次有时间再说,还望大家多多指教啊。有问题请在下面说就可以了。