文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>1.1 访问字符串的子串

1.1 访问字符串的子串

时间:2006-12-26  来源:xiaoshengcaicai

1.1 访问字符串的子串

1.1.1 问题

你想访问或者修改字符串的一部分,但不是整个字符串。比如,你刚读到了一个固定宽度的记录,你想把它的每个字段的值都提取出来。

1.1.2 解决方案

函数substr让你可以读写字符串的某个特定部分。

$value = substr($string, $offset, $count);
$value = substr($string, $offset);

substr($string, $offset, $count) = $newstring;
substr($string, $offset, $count, $newstring); # same as previous
substr($string, $offset) = $newtail;

函数unpack只提供了对字符串的只读访问,但是在你有很多子串要提取出来的时候速度比较快。

# get a 5-byte string, skip 3 bytes,
# then grab two 8-byte strings, then the rest;
# (NB: only works on ASCII data, not Unicode)
($leading, $s1, $s2, $trailing) =
unpack("A5 x3 A8 A8 A*", $data);

# split at 5-byte boundaries
@fivers = unpack("A5" x (length($string)/5), $string);

# chop string into individual single-byte characters
@chars = unpack("A1" x length($string), $string);

1.1.3 讨论

字符串是一种基本数据类型,它们不是某种基本数据类型的数组,在某些其他编程语言里面你可能会用数组的下标方法来访问字符串的某个字符,在Perl里面不能这样,你得用像unpack,substr这样得函数来访问字符串的某个字符或者某部分子串。

substr函数的offset参数指的是你想要得到的子串在字符串里面的开始位置,如果该参数为正值则是从字符串的左端开始算,如果是负值则是从字符串右端开始算。如果offset参数是0,那么子串就是从字符串左端开始。count参数是子串的长度。

$string = "This is what you have";
# +012345678901234567890 Indexing forwards (left to right)
# 109876543210987654321- Indexing backwards (right to left)
# note that 0 means 10 or 20, etc. above

$first = substr($string, 0, 1); # "T"
$start = substr($string, 5, 2); # "is"
$rest = substr($string, 13); # "you have"
$last = substr($string, -1); # "e"
$end = substr($string, -4); # "have"
$piece = substr($string, -8, 3); # "you"

substr函数不仅可以可让你读取字符串的某部分,还可以让你改变字符串的某部分的值。因为substr是一个特别的左值函数(particularly odd kind of function—an lvaluable one),所谓左值函数就是指函数的返回值本身可以被赋值。(还有其他正式的左值函数,vec,pos,keys),你也可以认为local,my,our这些也是左值函数。

$string = "This is what you have";
print $string;
This is what you have
substr($string, 5, 2) = "wasn't"; # change "is" to "wasn't"
This wasn't what you have
substr($string, -12) = "ondrous";# "This wasn't wondrous"
This wasn't wondrous
substr($string, 0, 1) = ""; # delete first character
his wasn't wondrous
substr($string, -10) = ""; # delete last 10 characters
his wasn'

把substr跟操作符=~, s///,m//,或者tr///结合在一起可以让这些操作符只对字符串的某部分发生作用。

# you can test substrings with =~
if (substr($string, -10) =~ /pattern/) {
print "Pattern matches in last 10 characters\n";
}

# substitute "at" for "is", restricted to first five characters
substr($string, 0, 5) =~ s/is/at/g;

你甚至可以使用在赋值语句两边都放上substr来实现字符串中2个子串的交换位置。

# exchange the first and last letters in a string
$a = "make a hat";
(substr($a,0,1), substr($a,-1)) =
(substr($a,-1), substr($a,0,1));
print $a;
take a ham

虽然unpack函数不是左值函数,但是当我们需要一次性从字符串里面提取多个子串的时候它比substr快。  指定一个记录的输出格式来进行unpack。为了确定子串的位置,使用小写的x跟一个数量来表示向前(向字符串尾端)跳过一些字节,使用大写的字母X跟一个数量来表示向后(向字符串首端)跳过一些字节,用@来跳到记录里的绝对偏移量位置(and an "@" to skip to an absolute byte offset within the record)。如果数据包含了Unicode字符串,你就要小心了,这3个操作是面向字节的,在多字节编码的数据里头进行字节为单位的移动是非常危险的。

# extract column with unpack
$a = "To be or not to be";
$b = unpack("x6 A6", $a); # skip 6, grab 6
print $b;
or not

($b, $c) = unpack("x6 A2 X5 A2", $a); # forward 6, grab 2; backward 5, grab 2
print "$b\n$c\n";
or
be

有时你更喜欢把你的数据切割成特定的几列。比如,你可能想从第8,14,20,26,30个位置之前进行切割,这些数字是每一列数据的开始位置。虽然你可以计算出正确的unpack格式是"A7 A6 A6 A6 A4 A*", 但是这对一个懒惰的Perl程序员来说太麻烦了,让Perl自己去搞定它吧,用下面这个函数cut2fmt:

function:

sub cut2fmt {
my(@positions) = @_;
my $template = '';
my $lastpos = 1;
foreach $place (@positions) {
$template .= "A" . ($place - $lastpos) . " ";
$lastpos = $place;
}
$template .= "A*";
return $template;
}

$fmt = cut2fmt(8, 14, 20, 26, 30);
print "$fmt\n";
A7 A6 A6 A6 A4 A*

这个强大的unpack函数在纯文本处理上面发挥了很大的作用。它是文本跟二进制数据的桥梁。T

在这个例子里面,我们假设了所有的字符数据(译者注:指程序代码的编码方式)都是7bits或者8bits的,所以pack的字节操作没什么问题。

1.1.4 参阅

函数pack, unpack, 和 substr 在perlfunc(1) 和 Programming Perl 的第29章; 函数cut2fmt将会在1.24这一节 被使用到; unpack在二进制上的使用在 8.24这一节

相关阅读 更多 +
排行榜 更多 +
太空飞船终极攻击

太空飞船终极攻击

飞行射击 下载
化作星辰

化作星辰

飞行射击 下载
枪战火柴人中文版

枪战火柴人中文版

飞行射击 下载