Common threads: Awk by example, Part 3
字符串函数和…支票?
概要:在awk系列的最后一篇,Daniel向你介绍awk重要的字符串函数并展示如何从开始写一个完整的支票结算程序。 一路走下来,你将学会如何写自己的函数以及如何使用awk的多维数组。本篇结束时,你将有更多的awk经验,可以编写更加强大的脚本。
格式化输出
尽管大多数时候awk的print语句都能满足要求,但有时还是不够。Awk还提供了两个很好用的老朋友printf()和sprintf()。是的,这些函数跟他们在C语言中的同名函数是一样的。printf()将在标准输出设备上打印一个格式化字符串,而sprintf()将返回一个格式化的字符串,这个返回值还可以赋给某个变量。 如果你还不熟悉printf()和sprintf(),找一本C语言的介绍性书来读一读,你将很快能了解这两个基本的函数。你也能在Linux系统上输入”man 3 printf”来查看printf()的man说明。
这儿是一些awk的sprintf()和printf()的代码例子。如你所见,所有用法看起来都跟C语言中一样:
x=1
b=”foo”
printf(“%s got a %d on the last test\n”,”Jim”,83)
myout=(“%s-%d”,b,x)
print myout
这个代码将打印:
Jim got a 83 on the last test
foo-1
字符串函数
Awk有很多的字符串函数,这是个好事。因为在awk中你不能像C、C++和python等其他语言一样,把字符串当做一个字符数组来处理,所以你真的很需要字符串函数。例如你执行下面的代码:
mystring=”How are you doing today?”
print mystring[3]
你将得到一个像下面一样的错误:
awk: string.gawk:59: fatal: attempt to use scalar as array
哦,好吧!尽管不如Python的序列类型方便,awk的字符串函数还是可以做这些工作的。让我们来看看这些函数。
首先,我们有基本的length()函数,它会返回字符串的长度。这儿是如何使用它的例子:
print length(mystring)
这段代码将打出下面的值:
24
OK,让我们继。下一个字符串函数叫index,他将返回一个子串在另一个字符串中出现的位置,如果找不到这个子串,就返回0。使用mystring作为例子,我们可以这样调用:
print index(mystring,”you”)
Awk打印:
9
我们继续来看两个更容易的函数, tolower() 和toupper()。你可能猜到了,这些函数将分别返回全部是大写或全部是小写的字符串。要注意的是tolower() 和toupper()返回新的字符串,而不是修改原来的字符串。这段代码:
print tolower(mystring)
print toupper(mystring)
print mystring
…将产生下面的输出:
how are you doing today?
HOW ARE YOU DOING TODAY?
How are you doing today?
到目前为止,一切顺利,但如果我想从字符串中提取一个子串或者甚至是单个字符,那该咋办呢?substr()函数就是干这个的。这儿显示如何调用substr():
mysub=substr(mystring,startpos,maxlen)
Mystring应该是你想从中提取子串的一个字符串变量或者是一个原始的字符串。 startpos应该设置为开始字符的位置。 maxlen 应该包含你想要提取的子串的最大长度。注意我说的最大长度;如果length(mystring)的值小于startpos+maxlen,你的结果将被截断。substr()不会修改原始字符串,而是返回一个新字符串。这儿是一个例子:
print substr(mystring,9,3)
Awk将打出:
You
如果你经常使用那些用数组索引来访问字符串的语言编程,那么要牢记awk中是用substr()来代替这种方法的。你将用它来提取单个字符和子串,因为awk是一个基于字符串的语言,你会经常用到它的。
现在,我们来继续看一些更棒的函数,第一个叫做match()。Match() 有点像index(),除了像index()一样搜索子串,他还可以搜索正则表达式。Match()将返回匹配项的开始点,或者返回0(如果找不到匹配项)。另外,math()也会设置两个变量,分别叫RSTART和RLENGTH。RSTART包含返回值(第一个匹配项的位置),RLENGTH指出匹配的字符长度(如果找不到匹配项,则为-1)。使用RSTART、RLENGTH、substr()和一个小的循环,你能很容易的在你的字符串中迭代每个匹配项。这儿是一个match()调用的例子:
print match(mystring,/you/), RSTART, RLENGTH
Awk将打印:
9 9 3
字符串替换
现在,我们来看两个字符串替换函数sub()和gsub()。这两个家伙跟我们已经见过的函数有些轻微不同的地方在于:他们实际修改原始字符串。这儿是个模版,显示如何调用sub():
sub(regexp,replstring,mystring)
当你调用sub()时,它将在mystring中找到第一个匹配regexp的字符序列,并使用replstring替换这个字符序列。sub()和gsub()有相同的参数,他们唯一的不同点在于,sub()只替换第一个匹配项(如果有匹配项的话),而gsub()将执行一个全局替换,替换字符串中的所有匹配项。这儿是一个调用sub()和bsub()的例子:
sub(/o/,”O”,mystring)
print mystring
mystring=”How are you doing today?”
gsub(/o/,”O”,mystring)
print mystring
因为第一个sub()直接修改了mystring,我们必须重置mystring到他的原始值。当执行上述的代码时,awk将输出下面的内容:
HOw are you doing today?
HOw are yOu dOing tOday?
当然,更加复杂的正则表达式也是可以的。我将留下来让你自己去测试一些复杂的正则表达式。
我们最后给你介绍一个叫做split()的函数,香港虚拟主机,以此来结束字符串函数的内容。Split()的工作是用来分割一个字符串,并将分割后的多个部分放入一个使用整数索引的数组中。这儿是一个split()调用的例子:
numelements=split(“Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec”,mymonths,”,”)
我不敢说我可以忘却,或者勇敢,坚强,等等等等一切堂皇而陈旧的字眼。