前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何将awk脚本移植到Python【Programming(Python)】

如何将awk脚本移植到Python【Programming(Python)】

作者头像
Potato
修改2019-11-18 12:00:03
1.3K0
修改2019-11-18 12:00:03
举报

从代码到代码风格,将awk脚本移植到Python

图片来源:kris krüg
图片来源:kris krüg

脚本是解决问题的有效方法,而awk是编写脚本的出色语言。 它特别擅长简单文本处理,并且它可以带您完成配置文件的某些复杂重写或目录中文件名的格式重新格式化。

何时从awk移至Python

到了某个时候,awk的局限性开始显现出来。它没有将文件分解为模块的实际概念,它、缺乏质量错误报告,并且缺少了现在被认为是语言工作原理的其他内容。当编程语言的这些丰富功能有助于维护关键脚本时,移植将是一个不错的选择。

我最喜欢的完美移植awk的现代编程语言是Python。

在将awk脚本移植到Python之前,通常值得考虑一下其原始上下文。 例如,由于awk的局限性,awk代码通常是从Bash脚本调用的,其中包括对其他命令行收藏夹(如sed,sort和gang)的一些调用。 最好将所有内容转换为一个一致的Python程序。 有时,脚本会做出过于宽泛的假设。 例如,即使实际上只运行一个文件,该代码也可能允许任意数量的文件。

在仔细考虑了上下文并确定了要用Python替代的东西之后,该编写代码了。

标准awk到Python

请记住以下Python代码:

代码语言:python
复制
with open(some_file_name) as fpin:
 for line in fpin:
 pass # do something with line

此代码将逐行循环遍历文件并处理这些行。

如果要访问行号(相当于awk的NR ),则可以使用以下代码:

代码语言:python
复制
with open(some_file_name) as fpin:
 for nr, line in enumerate(fpin):
 pass # do something with line

在 Python 中的多个文件上执行类 awk 行为

如果您需要能够遍历任意数量的文件同时保持行数的持续计数(例如awk的FNR ),那么此循环可以做到这一点:

代码语言:python
复制
def awk_like_lines(list_of_file_names):
 def _all_lines():
 for filename in list_of_file_names:
 with open(filename) as fpin:
 yield from fpin
yield from enumerate(_all_lines())

该语法使用Python的生成器和yield from来构建遍历所有行并保持持久计数的迭代器 。

如果你同时需要 FNR 和 NR,这里有一个更复杂的循环:

代码语言:python
复制
def awk_like_lines(list_of_file_names):
 def _all_lines():
 for filename in list_of_file_names:
  with open(filename) as fpin:
 yield from enumerate(fpin)
 for nr, (fnr, line) in _all_lines:
 yield nr, fnr, line

具有FNR,NR和line的更复杂的awk功能

问题仍然是你是否需要所有三个功能:FNR,NR 和线。 如果你真的这样做,使用三元组,其中两个项目是数字可能会导致混淆。 命名参数可以使代码更容易阅读,所以最好使用一个数据类:

代码语言:python
复制
import dataclass
@dataclass.dataclass(frozen=True)
class AwkLikeLine:
 content: str
 fnr: int
 nr: int
def awk_like_lines(list_of_file_names):
 def _all_lines():
 for filename in list_of_file_names:
 with open(filename) as fpin:
 yield from enumerate(fpin)
 for nr, (fnr, line) in _all_lines:
 yield AwkLikeLine(nr=nr, fnr=fnr, line=line)

你可能会想,为什么不从这个方法开始呢? 从其他地方开始的原因是,这几乎太复杂了。 如果您的目标是使通用库更容易将awk移植到Python,请考虑这样做。但是编写一个循环,使您能够准确地得到特定情况下所需要的内容更容易,也更容易理解(因此也更容易维护)。

了解awk字段

一旦拥有与一行相对应的字符串,如果要转换awk程序,通常需要将其分解为多个字段。Python有几种方法可以做到这一点。 这将返回一个字符串列表,在任意数量的连续空格上分割该行:

代码语言:python
复制
line.split()

如果需要另一个字段分隔符,比如使用’:’ 和’;’,则需要 rstrip 方法来删除最后一个换行符:

代码语言:python
复制
line.rstrip("\n").split(":")

在执行以下操作之后,列表parts将具有分解的字符串:

代码语言:python
复制
parts = line.rstrip("\n").split(":")

这种拆分对于选择如何处理这些参数是有好处的,但是我们处于了一个错误的情况下。现在parts[0]将对应 awk 的 $1,parts[1]将对应 awk 的 $2,依此类推。之所以出现这种情况是因为awk从1开始计数“字段”,而Python从0开始计数。 在 awk 的 $0中是整个行——相当于 line.rstrip("\n") ,而且awk的NF (字段数)更容易作为len(parts)检索。

在Python中移植awk字段

作为一个示例,让我们将《如何用 awk 删除文件中的重复行》中的一行代码转换为 Python。

最初的 awk 是:

代码语言:javascript
复制
awk '!visited$0++' your_file > deduplicated_file

“真正的” Python 转换是:

代码语言:python
复制
import collections

import sys

visited = collections.defaultdict(int)

for line in open("your\_file"):

 did\_visit = visited[line]

 visited[line] += 1

 if not did\_visit:

 sys.stdout.write(line) 

然而,Python 比 awk 有更多的数据结构。 与其计算访问次数(我们不使用这个,除了知道我们是否看到了一行),为什么不记录被访问的行呢?

代码语言:python
复制
import sys
visited = set()
for line in open("your_file"):
 if line in visited:
 continue
 visited.add(line)
sys.stdout.write(line)

编写 Pythonic awk 代码

Python社区提倡编写Pythonic代码,这意味着它遵循公认的代码风格。 更加Python化的方法将区分唯一性和输入/输出的关注点。 此更改将使对代码进行单元测试更加容易:

代码语言:python
复制
def unique_generator(things):
 visited = set()
 for thing in things:
 if thing in visited:
 continue
 visited.add(things)
 yield thing
import sys
for line in unique_generator(open("your_file")):
sys.stdout.write(line)

将所有逻辑从输入 / 输出代码中移除,可以提高代码的关注点分离和可用性和可测试性。

结论: Python 是一个不错的选择

将awk脚本移植到Python时,通常是在考虑适当的Python代码风格时重新实现核心需求,而不是通过条件/操作对条件/操作进行笨拙的翻译。 考虑原始上下文并产生高质量的Python解决方案。 虽然有时候使用awk的Bash单行代码可以完成工作,但是Python编码是通往更易于维护的代码的途径。

另外,如果您正在编写awk脚本,我相信您也可以学习Python! 如果您有任何疑问,请告诉我。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 何时从awk移至Python
  • 标准awk到Python
  • 在 Python 中的多个文件上执行类 awk 行为
  • 具有FNR,NR和line的更复杂的awk功能
  • 了解awk字段
  • 在Python中移植awk字段
  • 编写 Pythonic awk 代码
  • 结论: Python 是一个不错的选择
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档