当您学习一门新的编程语言时,最好关注大多数编程语言的共同之处
- 变量 – 存储信息的地方
- 表达式 – 计算事物的方法
- 语句 – 在程序中表达状态变化的方式
这些概念是大多数编程语言的基础。
一旦您理解了这些概念,就可以开始弄清楚其余的内容。例如,大多数语言都有其设计支持的“做事方式”,这些方式可能因程序而异。这些方式包括模块化(将相关功能组合在一起)、声明式与命令式、面向对象、低级与高级语法特性等等。许多程序员熟悉的一个例子是“仪式感”,即在解决问题之前设置场景所需的工作量。据说 Java 编程语言具有显著的仪式感要求,这源于其设计,它要求所有代码都必须在类中定义。
回到基础知识。编程语言通常具有相似之处。一旦您掌握了一种编程语言,就可以从学习另一种语言的基础知识开始,以体会新语言的差异。
一个好的方法是创建一组基本的测试程序。有了这些,学习就从这些相似之处开始。
您可以使用的一个测试程序是“猜数字”程序。计算机选择一个介于 1 到 100 之间的数字,并要求您猜这个数字。程序循环直到您猜对为止。
“猜数字”程序练习了编程语言中的几个概念
- 变量
- 输入
- 输出
- 条件评估
- 循环
这是一个学习新编程语言的绝佳实践实验。
注意:本文改编自 Moshe Zadka 关于在 Julia 中使用此方法的文章和 Jim Hall 关于在 Bash 中使用此方法的文章。
用 awk 猜数字
让我们编写一个“猜数字”游戏作为 Awk 程序。
Awk 是动态类型的,是一种面向数据转换的脚本语言,并且对交互式使用具有出色的支持。Awk 自 1970 年代以来就已存在,最初是 Unix 操作系统的一部分。如果您不了解 Awk 但喜欢电子表格,这是一个信号…… 去学习 Awk!
您可以从编写一个“猜数字”游戏的版本开始探索 Awk。
这是我的实现(带有行号,以便我们可以查看一些具体功能)
1 BEGIN {
2 srand(42)
3 randomNumber = int(rand() * 100) + 1
4 print "random number is",randomNumber
5 printf "guess a number between 1 and 100\n"
6 }
7 {
8 guess = int($0)
9 if (guess < randomNumber) {
10 printf "too low, try again:"
11 } else if (guess > randomNumber) {
12 printf "too high, try again:"
13 } else {
14 printf "that's right\n"
15 exit
16 }
17 }
我们可以立即看到 Awk 控制结构与 C 或 Java 的结构之间的相似之处,但与 Python 不同。在诸如 if-then-else 或 while 之类的语句中,then、else 和 while 部分采用语句或用 { 和 } 括起来的一组语句。但是,关于 AWk 有一个很大的区别需要从一开始就理解
从设计上讲,Awk 是围绕数据管道构建的。
这意味着什么?大多数 Awk 程序都是代码片段,它们接收一行输入,对数据进行一些处理,然后将其写入输出。认识到对此类转换管道的需求,Awk 默认提供了所有转换管道。让我们通过提出一个基本问题来探索上述程序:'从控制台读取数据' 结构在哪里?
答案是 – 它是内置的。特别是,第 7 – 17 行告诉 Awk 如何处理读取的每一行。鉴于这种情况,很容易看出第 1 – 6 行在读取任何数据之前执行。
更具体地说,第 1 行上的 BEGIN 关键字是一种“模式”,在这种情况下,它指示 Awk 在读取任何数据之前,应执行 BEGIN 后面的 { … } 中的内容。类似的 END 关键字(在此程序中未使用)指示 Awk 在读取完所有内容后应执行的操作。
回到第 7 – 17 行,我们看到它们创建了一个代码块 { … },该代码块类似,但前面没有关键字。由于 { 前面没有任何内容供 Awk 匹配,因此它会将此行应用于接收到的每一行输入。每一行输入都将作为用户的猜测输入。
让我们看看正在执行的代码。首先,在读取任何输入之前发生的序言。
在第 2 行中,我们使用数字 42 初始化随机数生成器(如果我们不提供参数,则使用系统时钟)。42? 当然是 42。第 3 行计算一个介于 1 和 100 之间的随机数,第 4 行出于调试目的打印出该数字。第 5 行邀请用户猜一个数字。请注意,此行使用 printf
,而不是 print
。与 C 类似,printf
的第一个参数是用于格式化输出的模板。
现在用户知道程序期望输入,她可以在控制台上键入一个猜测。如前所述,Awk 将此猜测提供给第 7 – 17 行中的代码。第 18 行将输入记录转换为整数;$0
表示整个输入记录,而 $1
表示输入记录的第一个字段,$2
表示第二个字段,依此类推。是的,Awk 使用预定义的分隔符(默认为空格)将输入行拆分为组成字段。第 9 – 15 行将猜测与随机数进行比较,打印适当的响应。如果猜测正确,则第 15 行过早地退出输入行处理管道。
简单!
鉴于 Awk 程序的异常结构,即代码片段对特定的输入行配置做出反应并处理数据,让我们看看另一种结构,只是为了了解过滤部分是如何工作的
1 BEGIN {
2 srand(42)
3 randomNumber = int(rand() * 100) + 1
4 print "random number is",randomNumber
5 printf "guess a number between 1 and 100\n"
6 }
7 int($0) < randomNumber {
8 printf "too low, try again: "
9 }
10 int($0) > randomNumber {
11 printf "too high, try again: "
12 }
13 int($0) == randomNumber {
14 printf "that's right\n"
15 exit
16 }
第 1 – 6 行没有改变。但是现在我们看到第 7 – 9 行是当行的整数值小于随机数时执行的代码,第 10 – 12 行是当行的整数值大于随机数时执行的代码,第 13 – 16 行是当两者匹配时执行的代码。
这应该看起来“酷但怪异” – 例如,我们为什么要重复计算 int($0)
?当然,这将是一种解决问题的奇怪方法。但是,这些模式可能是分离条件处理的非常好的方法,因为它们可以采用正则表达式或 Awk 支持的任何其他结构。
为了完整起见,我们可以使用这些模式将公共计算与仅适用于特定情况的事物分开。这是第三个版本来说明
1 BEGIN {
2 srand(42)
3 randomNumber = int(rand() * 100) + 1
4 print "random number is",randomNumber
5 printf "guess a number between 1 and 100\n"
6 }
7 {
8 guess = int($0)
9 }
10 guess < randomNumber {
11 printf "too low, try again: "
12 }
13 guess > randomNumber {
14 printf "too high, try again: "
15 }
16 guess == randomNumber {
17 printf "that's right\n"
18 exit
19 }
认识到无论输入什么值,都需要将其转换为整数,我们创建了第 7 – 9 行来执行此操作。现在,三组行,10 – 12、13 – 15 和 16 – 19,引用了已定义的变量 guess,而不是每次都转换输入行。
让我们回到我们想要学习的事物列表
- 变量 – 是的,Awk 有这些;我们可以推断输入数据以字符串形式输入,但在需要时可以转换为数值
- 输入 – Awk 只是通过其“数据转换管道”方法发送输入来读取内容
- 输出 – 我们使用了 Awk 的
print
和printf
过程来将内容写入输出 - 条件评估 – 我们了解了 Awk 的 if-then-else 和响应特定输入行配置的输入过滤器
- 循环 – 咦,想象一下!我们这里不需要循环,再次感谢 Awk 采用的“数据转换管道”方法;循环“自然而然地发生”。请注意,用户可以通过向 Awk 发送文件结束信号(在使用 Linux 终端窗口时为 CTRL-D)来过早退出管道
值得考虑不需要循环来处理输入的重要性。Awk 长期以来一直可行的原因之一是 Awk 程序很紧凑,而它们紧凑的原因之一是无需样板代码即可从控制台或文件读取。
让我们运行程序
$ awk -f guess.awk
random number is 25
guess a number between 1 and 100: 50
too high, try again: 30
too high, try again: 10
too low, try again: 25
that's right
$
我们没有涵盖的一件事是注释。Awk 注释以 #
开头,以行尾结尾。
总结
Awk 非常强大,这个“猜数字”游戏是入门的好方法。但这不应该是您旅程的终点。您可以 阅读 Awk 和 Gawk (GNU Awk) 的历史,Gawk 是 Awk 的扩展版本,如果您运行 Linux,它可能是您计算机上的版本,或者 阅读其初始开发人员关于原始版本的所有信息。
您还可以 下载我们的速查表,以帮助您跟踪您学习的所有内容。
4 条评论