如何使用re模块解析文本文件中的颜色名称?

How to use re module to parse color names in text file?

我需要阅读文件 src/rgb.txt,其中包含颜色的名称及其 RGB 格式的数字表示(该文件仅部分显示在下方)。每行包含四个字段:红色、绿色、蓝色和颜色名称,每个字段由一定数量的白色分隔space(制表符或space)。

我尝试使用 Python 的正则表达式(必须使用 re !)编写一个函数来读取文件并且应该 return 一个字符串列表,以便在 returned 列表它们有四个字段,由单个制表符 (\t) 分隔。 returned 列表中的第一个字符串应该是: '255\t250\t250\tsnow'.

文本文件:

255 250 250     snow
248 248 255     ghost white
248 248 255     GhostWhite
245 245 245     white smoke
245 245 245     WhiteSmoke
220 220 220     gainsboro
255 250 240     floral white
255 250 240     FloralWhite

到目前为止,我的代码如下所示:

import re

def red_green_blue(filename='src/rgb.txt'):
    with open('src/rgb.txt', "r") as f:
        for line in f:
            line = f.read().splitlines()
            for i in range(len(line)):
                new_line = re.sub("^\t+|\t+$", "", str(line[i]), flags=re.UNICODE)
                d1 = " ".join(re.split("\t+", str(new_line), flags=re.UNICODE))
                print(d1, type(d1))
        return d1

我想知道是否有其他方法可以使用其他正则表达式来解决此任务,例如findallsearch

我还想知道如何显示 \t,因为在我的例子中,我看到的是制表符,但不是 \t,即 169 169 169 DarkGray 而不是 169\t169\t169\tDarkGray

这个怎么样:

[ \t]*(\d+)[ \t]*(\d+)[ \t]*(\d+)[ \t]*(.*)

由于您是逐行迭代文件,因此无需考虑换行,只需关注单行。

另外,假设第一行 ! $Xorg: 确实存在于文件中并将跳过它 - 因为我是 linux 中的新手所以我不知道那是什么或者是合法的一部分文件。

import re


def parse_re_gen(filename):
    regex = re.compile(r"[ \t]*(\d+)[ \t]*(\d+)[ \t]*(\d+)[ \t]*(.*)")

    with open(filename) as f:  # "r" = "rt" and already default, no need to specify.
        for line in f:
            try:
                yield regex.match(line).groups()
            except AttributeError:  # first line " ! $Xorg:~~~ " falls here.
                pass


def wrapped_re():
    for record in parse_re_gen():
        # print(record)
        print(repr("\t".join(record)))

wrapped_re()

生成器parse_re_gen 将return 逐行匹配元组。您的 teacher/professor 可能想要这个。在循环后调用 return 只会 return 最后一行。

('0', '139', '139', 'DarkCyan')
('139', '0', '139', 'dark magenta')
('139', '0', '139', 'DarkMagenta')
('139', '0', '0', 'dark red')
('139', '0', '0', 'DarkRed')

wrapped_re 将遍历生成器,将生成的元组与制表符作为分隔符连接起来,并通过使用 repr(str).

打印出原始制表符
'0\t139\t139\tDarkCyan'
'139\t0\t139\tdark magenta'
'139\t0\t139\tDarkMagenta'
'139\t0\t0\tdark red'
'139\t0\t0\tDarkRed'

旧的替代方式

将此视为 xy 问题时:为什么首先使用 re

没有 re 模块,一切都变得更简单、更快捷。

def parse_rgb_gen(filename):

    with open(filename) as fp:
        for line in fp:
            print(repr(output := "\t".join(line.split())))
            # do something with output

timeit.timeit 结果:

without re: 2.365
with    re: 3.116

部分输出:

'139\t0\t139\tdark\tmagenta'
'139\t0\t139\tDarkMagenta'
'139\t0\t0\tdark\tred'
'139\t0\t0\tDarkRed'
'144\t238\t144\tlight\tgreen'
'144\t238\t144\tLightGreen'

最好将其转换为generator并在for循环中用于封装。

def parse_rgb_gen(filename="source.txt"):

    with open(filename) as fp:
        for line in fp:
            yield "\t".join(line.split())

for item in parse_rgb_gen():
    repr(item)

仅供参考:最后,假设以下是正确的解决方案(顺便说一句,如果没有堆栈溢出社区的帮助,我不会实现这个!):

import re

def red_green_blue(filename='src/rgb.txt'):
    with open('src/rgb.txt') as f:
        for line in f:
            line = f.read()
            regex = re.findall(r"[ \t]*(\d+)[ \t]*(\d+)[ \t]*(\d+)[ \t]*(.*)", line)
            #print(regex)
            string_list = list(map('\t'.join, regex))
            print(string_list)
        return string_list

谢谢。