百科狗-知识改变命运!
--

如何把awk脚本移植到Python

百变鹏仔1年前 (2023-11-21)阅读数 11#技术干货
文章标签代码

将一个awk脚本移植到Python主要在于代码风格而不是转译。

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

何时从awk转向Python

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

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

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

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

标准awk到Python功能

以下Python功能是有用的,需要记住:

withopen(some_file_name)asfpin:

forlineinfpin:

pass#dosomethingwithline

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

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

withopen(some_file_name)asfpin:

fornr,lineinenumerate(fpin):

pass#dosomethingwithline

在Python中实现多文件的awk式行为

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

defawk_like_lines(list_of_file_names):

def_all_lines():

forfilenameinlist_of_file_names:

withopen(filename)asfpin:

yieldfromfpin

yieldfromenumerate(_all_lines())

此语法使用Python的生成器和yieldfrom来构建迭代器,该迭代器将遍历所有行并保持一个持久计数。

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

defawk_like_lines(list_of_file_names):

def_all_lines():

forfilenameinlist_of_file_names:

withopen(filename)asfpin:

yieldfromenumerate(fpin)

fornr,(fnr,line)in_all_lines:

yieldnr,fnr,line

更复杂的FNR、NR和行数的awk行为

如果FNR、NR和行数这三个你全都需要,仍然会有一些问题。如果确实如此,则使用三元组(其中两个项目是数字)会导致混淆。命名参数可使该代码更易于阅读,因此最好使用dataclass:

importdataclass

@dataclass.dataclass(frozen=True)

classAwkLikeLine:

content:str

fnr:int

nr:int

defawk_like_lines(list_of_file_names):

def_all_lines():

forfilenameinlist_of_file_names:

withopen(filename)asfpin:

yieldfromenumerate(fpin)

fornr,(fnr,line)in_all_lines:

yieldAwkLikeLine(nr=nr,fnr=fnr,line=line)

你可能想知道,为什么不一直用这种方法呢?使用其它方式的的原因是总用这种方法太复杂了。如果你的目标是把一个通用库更容易地从awk移植到Python,请考虑这样做。但是编写一个可以使你确切地了解特定情况所需的循环的方法通常更容易实现,也更容易理解(因而易于维护)。

理解awk字段

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

line.split()

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

line.rstrip("\n").split(":")

完成以下操作后,列表parts将存有分解的字符串:

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)的形式得到。

如何把awk脚本移植到Python

移植awk字段到Python

例如,让我们将这个单行代码“如何使用awk从文件中删除重复行”转换为Python。

awk中的原始代码是:

awk'!visited[$0]++'your_file>deduplicated_file

“真实的”Python转换将是:

importcollections

importsys

visited=collections.defaultdict(int)

forlineinopen("your_file"):

did_visit=visited[line]

visited[line]+=1

ifnotdid_visit:

sys.stdout.write(line)

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

importsys

visited=set()

forlineinopen("your_file"):

iflineinvisited:

continue

visited.add(line)

sys.stdout.write(line)

编写Python化的awk代码

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

defunique_generator(things):

visited=set()

forthinginthings:

ifthinginvisited:

continue

visited.add(things)

yieldthing

importsys

forlineinunique_generator(open("your_file")):

sys.stdout.write(line)

将所有逻辑置于输入/输出代码之外,可以更好地分离问题,并提高代码的可用性和可测试性。

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

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

以上内容为大家介绍了如何把awk脚本移植到Python,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注IT培训机构:开发教育。http://www.baikegou.com/

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)