打印特定模式之间的行
我想要打印出特定字符串之间的内容,我的字符串如下:
my_string = '''
##start/file1
file/images/graphs/main
file/images/graphs
file/graphs
##start/new
new/pattern/symbol
new/pattern/
##start/info/version
version/info/main
version/info/minor
##start
values/key
values
...
... '''
在这个字符串中,我想搜索“main”,并把它打印出来,格式如下:
##start/file1/file/images/graphs/main
##start/info/version/version/info/main
我该怎么做呢?我试着在两个##start之间找到行,并搜索main。
2 个回答
有一种方法可以用Python的正则表达式解析器来实现,简称为regex。
简单来说,regex是一种用于在字符串中查找特定模式的语言。如果我有一个字符串'Hello, World'
,它会匹配正则表达式模式'llo, Wor'
,因为这个模式包含了一个“l”,后面跟着另一个“l”,再后面是一个“o”,然后是一个逗号和一个空格,接着是一个大写的“W”,依此类推。表面上看,这就像是在测试子字符串。正则表达式的真正强大之处在于它的特殊字符。如果我再次使用字符串'Hello, World'
,它也会匹配模式'Hello, \w\w\w\w\w'
,因为\w
是一个特殊字符,代表字母表中的任何字母(还有一些额外的字符)。所以'Hello, Bobby'
、'Hello, World'
、'Hello, kitty'
都能匹配模式'Hello, \w\w\w\w\w'
,因为\w
可以代表任何字母。还有很多这样的“特殊字符”,它们都非常有用。为了回答你的问题,
我构造了一个匹配的模式
##start\textICareAbout
file_I_don't_care
file_I_don't_care
file_I_care_about\main
这个模式是
r'(##start{line}){line}*?(.*main)'.format(line=r'(?:.*\n)')
开头的r表示这个字符串是一个原始字符串(这样我们就不需要在换行符前面加双反斜杠,具体可以查看链接的网页)。然后,括号中的内容变成了一个组。组是我们想要稍后能够回忆起来的文本片段。这里有两个组。第一个是(##start{line})
,第二个是(.*main)
。第一个组匹配任何以##start
开头并且持续整整一行的内容,比如
##start/file1
或##start/new
。
第二个组匹配以main结尾的行,因为.*
匹配除了换行符以外的所有字符。在这两个组之间有{line}*
,意思是“匹配任何完整的行,并且可以匹配任意数量的行”。所以把这些结合起来,我们得到:
匹配任何以##start
开头的内容,然后匹配任意数量的行,最后匹配任何以main结尾的行。
import re
# define my_string here
pattern = re.compile(r'(##start{line}){line}*?(.*main)'.format(line=r'(?:.*\n)'))
for match in pattern.findall(my_string):
string = match[0][:-1] # don't want the trailing \n
string += '/'
string += match[1]
print string
对于你的例子,它输出
##start/file1/file/images/graphs/main
##start/new/version/info/main
所以正则表达式非常酷,其他语言也有这个功能。它是一个非常强大的工具,你应该学习如何使用它,可以在这里找到相关资料。另外,我想提一下,我使用.format函数,因为我觉得它看起来更整洁、更易读,所以
'hello{line}world'.format(line=r'(?:.*\n)')
会被计算为'hello(?:.*\n)world'
,并且它会匹配
hello
Any Text Here. Anything at all. (just for one line)
world
你可以试试下面这样的代码:
def get_mains(my_string):
section = ''
for line in my_string.split('\n'):
if line[0:7] == "##start":
section = line
continue
if 'main' in line:
yield '/'.join([section, line])
for main in get_mains(my_string):
print main