
1. 题目考点
这道题主要考 4 个点:
- 正则表达式
re.findall() - 字符串切割
split() - 用布尔变量记录状态,比如
inside_block - 审题时区分:看起来像颜色代码,不一定真的要输出
这题最容易错的地方是:#BED、#Cab 这种虽然符合 HEX 颜色格式,但它们出现在 CSS 选择器位置,不是在 { } 里面,所以不能输出。
2. 审题
题目给你 N 行 CSS 代码,让你从上到下找出合法的 HEX 颜色代码。
合法 HEX 颜色代码满足:
以 # 开头
后面是 3 位或 6 位
每一位只能是 0-9、a-f、A-F
例如:
#FFF
#025
#F0A1FB
不合法的例子:
#ffffab # 6 位以外,多了
#abcf # 4 位
#12365erff # 含有 r,而且整体太长
但本题还有一个 CSS 语境限制:只输出 CSS 属性值里的颜色代码,不输出选择器里的颜色代码。
例如:
#BED
{
color: #FfFdF8;
}
这里:
#BED
是选择器,不输出。
#FfFdF8
在 { } 里面,是属性值,输出。
3. 思路提示
这题不要一上来就只想“写一个正则”。应该分两层想:
第一层,先判断当前这一行是不是在 CSS 代码块 { } 里面。
第二层,只在 { } 里面的内容中,用正则找合法颜色代码。
所以我们需要一个变量:
inside_block = False
它表示“当前是否已经进入 CSS 的 { } 代码块”。
遇到 {,说明进入 CSS 块:
inside_block = True
遇到 },说明离开 CSS 块:
inside_block = False
然后,只在 inside_block == True 的时候查找颜色代码。
4. 完整设计思路
第一步:读取输入行数
第一行是 N,表示后面有多少行 CSS 代码。
n = int(input().strip())
这里可以理解为:
读取第一行输入,并转成整数
第二步:准备正则表达式
合法颜色是:
# + 3 位十六进制数字
或者
# + 6 位十六进制数字
可以写成:
pattern = r'#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?(?![A-Za-z0-9])'
分开看:
# 必须以 # 开头
[0-9a-fA-F]{3} 先匹配 3 位合法字符
(?:...)? 后面可以再跟 3 位,也可以不跟
(?![A-Za-z0-9]) 后面不能继续跟字母或数字
最后这个 (?![A-Za-z0-9]) 很重要。
它是为了防止这种情况:
#12365erff
如果没有限制,程序可能会错误地把前面的 #12365e 当成合法颜色。实际上它后面还连着 rff,所以整个东西不应该被截断匹配。
第三步:只查 CSS 块内部
CSS 的基本结构是:
Selector
{
Property: Value;
}
所以我们只应该查 { 和 } 中间的内容。
这就是为什么要这样写:
if "{" in line:
inside_block = True
search_area = line.split("{", 1)[1]
这句话的意思是:如果这一行出现了 {,说明从 { 后面开始才是 CSS 块内容。
例如:
line = "div { color: #fff; }"
执行:
line.split("{", 1)
结果是:
["div ", " color: #fff; }"]
[1] 表示取 { 后面的部分:
" color: #fff; }"
因为 { 前面的 div 是选择器,不应该查颜色。
然后还要处理 }:
if "}" in search_area:
search_area = search_area.split("}", 1)[0]
inside_block = False
例如:
search_area = " color: #fff; }"
执行:
search_area.split("}", 1)
结果是:
[" color: #fff; ", ""]
[0] 表示取 } 前面的部分:
" color: #fff; "
因为 } 后面的内容已经离开 CSS 块,也不应该查。
第四步:为什么要先处理 {,再处理 }
顺序很关键。
假设有一行:
#main { color: #fff; }
这一行里面同时有选择器 #main 和颜色值 #fff。
我们真正要查的是:
color: #fff;
所以必须先用 { 切掉前面的选择器:
search_area = line.split("{", 1)[1]
得到:
color: #fff; }
然后再用 } 切掉后面的部分:
search_area = search_area.split("}", 1)[0]
得到:
color: #fff;
最后只在这一小段里面查颜色,就不会把选择器 #main 错误输出。
5. 代码实现
import re
if __name__ == "__main__":
n = int(input().strip())
pattern = r'#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?(?![A-Za-z0-9])'
inside_block = False
for _ in range(n):
line = input()
search_area = ""
# 如果这一行出现 {,说明从 { 后面开始进入 CSS 块
if "{" in line:
inside_block = True
search_area = line.split("{", 1)[1]
# 如果已经在 CSS 块里面,就检查整行
elif inside_block:
search_area = line
# 如果搜索区域里出现 },说明只查 } 前面的内容
if "}" in search_area:
search_area = search_area.split("}", 1)[0]
inside_block = False
# 在真正的 CSS 块内容中查找合法 HEX 颜色
colors = re.findall(pattern, search_area)
for color in colors:
print(color)
6. 运行演示
看样例中的一部分:
#BED
{
color: #FfFdF8; background-color:#aef;
font-size: 123px;
background: -webkit-linear-gradient(top, #f9f9f9, #fff);
}
第一行:
#BED
这时还没有进入 { },所以:
inside_block = False
不查这一行,所以 #BED 不输出。
第二行:
{
遇到 {,进入 CSS 块:
inside_block = True
第三行:
color: #FfFdF8; background-color:#aef;
现在在 CSS 块里面,所以用正则查找,找到:
#FfFdF8
#aef
第四行:
font-size: 123px;
没有 HEX 颜色,不输出。
第五行:
background: -webkit-linear-gradient(top, #f9f9f9, #fff);
找到:
#f9f9f9
#fff
遇到 } 后,离开 CSS 块:
inside_block = False
所以最后输出类似:
#FfFdF8
#aef
#f9f9f9
#fff
#ABC
#fff
注意,样例里的:
#BED
#Cab
都不输出,因为它们是选择器,不是 CSS 属性值。
7. 方法总结
这一类题不要只盯着正则。正确做法是先问自己:
我要匹配的东西,是否有出现位置限制?
这道题的限制就是:
只匹配 CSS 块内部的颜色代码
所以解题顺序应该是:
先确定范围
再写正则
最后输出匹配结果
可以总结成一句话:
状态变量 inside_block 负责判断“能不能查”,正则 pattern 负责判断“是不是合法颜色”。
8. 练习
请你尝试判断下面这段 CSS 应该输出哪些 HEX 颜色代码。
8
#header
{
color: #ABCDEF;
border-color: #abcd;
background: #123;
}
#footer
{
color: #12g;
}
提示:
#header、#footer是选择器,不输出。#ABCDEF是 6 位合法 HEX。#abcd是 4 位,不合法。#123是 3 位合法 HEX。#12g里面有g,不合法。



