0

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

我尝试使用 Python 的正则表达式(必须使用 re !)编写一个函数,该函数读取文件并应返回字符串列表,因此在返回的列表中它们有四个字段,由单个制表符 ( \t) 分隔。返回列表中的第一个字符串应该是: '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

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

我还想知道如何显示\t,因为在我的情况下,我看到标签,但不是作为\t,即169 169 169 DarkGray而不是169\t169\t169\tDarkGray

4

2 回答 2

1

这个怎么样:

[ \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只会返回最后一行。

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

并将wrapped_re通过生成器进行迭代,将生成的元组与 tab 作为分隔符连接,并通过使用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)
于 2020-10-31T14:48:31.530 回答
0

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

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

谢谢你。

于 2020-11-01T17:36:02.013 回答