Python业余爱好者。我有一个文本文件列出了数千行的信息,我试图根据它们是否与模式匹配来选择一行和以下2-3行。 我已将文件从原始文件中过滤掉,只包含我感兴趣的文件部分,因此我的当前文件如下所示:
trig1.RESP:
stim4: silence.wav
trig1.RESP:
trig6.RESP: 1
trig1.RESP:
trig1.RESP:
trig5.RESP: 1
stim5: silence.wav
trig1.RESP:
trig6.RESP: 1
stim3: silence.wav
trig1.RESP:
stim5: silence.wav
trig1.RESP:
trig6.RESP: 1
依此类推...... 基本上我要做的就是写出包含该行的silence.wav部分的每一行,然后写下它后面的两行。我使用了以下代码:
parsed_output = open("name-of-file-to-be-written", "w")
filtered_input = open("name-of-file-that-has-above-data", "r")
for line in filtered_input:
if "silence.wav" in line and "trig1" in filtered_input.next():
parsed_output.write(line)
parsed_output.write(filtered_input.next())
parsed_output.close()
这大部分工作正常,因为它打印的是silence.wav行和有响应的行(我最感兴趣的部分,此时响应之前的trig1不太重要)。然而,我遇到的问题是线路何时出现:
stim3: silence.wav
trig1.RESP:
stim5: silence.wav
由于我的输出将写入stim3(当前行)和stim5(跳过trig1后的下一行),我认为它会转到下一个“stim:silence.wav”并跳过stim5,因为它包含在写入时的上一个命令。 我想在trig5之后使用trig6.RESP:1,但是由于我描述的原因,我的输出没有显示出来。 有没有办法可以让它不跳过那个刺激?
对不起,如果这真的很长。提前谢谢!
答案 0 :(得分:4)
这样的事情怎么样? (完全未经测试)
count = 3
for line in filtered_input:
if "silence.wav" in line:
count = 0
else:
count += 1
if count <= 2:
filtered_output.write(line)
这不是很花哨,但我认为它应该非常强大。
答案 1 :(得分:2)
我尝试将此翻译为伪代码说:
For each (Line) {
If Next Line is "Trig1" AND Current Line is "silence.wav"
Log it
}
## And We're Done
(请随时在此纠正我)
你错过了Trig6,因为你要求下一行不存在。您可以在向后推荐而不是向前推荐的地方重写它并解决问题吗?
答案 2 :(得分:1)
一种可能的方法是使用deque,以便您可以一次跟踪三行:
import collections
parsed_output = open("name-of-file-to-be-written", "w")
filtered_input = open("name-of-file-that-has-above-data", "r")
window = collections.deque([None]*3, maxlen=3)
for line in filtered_input:
window.append(line)
if 'silence.wav' in window[0]:
parsed_output.write(window[0])
# only output next two lines if they don't also contain 'silence.wav'
if 'silence.wav' not in window[1]:
parsed_output.write(window[1])
if 'silence.wav' not in window[2]:
parsed_output.write(window[2])
# following if/elif in case last or second to last line contain 'silence.wav'
if 'silence.wav' in window[1]:
parsed_output.write(window[1])
parsed_output.write(window[2])
elif 'silence.wav' in window[2]:
parsed_output.write(window[2])
parsed_output.close()
如果您为deque提供maxlen
参数,那么当您向一端添加其他元素时,会从另一端弹出一个元素,例如:
>>> x = collections.deque([1, 2, 3], maxlen=3)
>>> x
deque([1, 2, 3], maxlen=3)
>>> x.append(4)
>>> x
deque([2, 3, 4], maxlen=3)
>>> x.append(5)
>>> x
deque([3, 4, 5], maxlen=3)
这允许您迭代文件,但以方便的方式保存您读取的最后3行,只要window
的第一个元素符合您的条件,只需输出匹配的行和以下两个只要他们不符合你的条件。
答案 3 :(得分:1)
你应该学习使用正则表达式(模块重新)
当人们想要分析文本时,它是强制性的。
了解它允许做什么:
import re
ss = """trig1.RESP:
stim4: silence.wav
trig1.RESP:
trig6.RESP: 1
trig1.RESP:
trig1.RESP:
trig5.RESP: 1
stim5: silence.wav
trig1.RESP:
trig6.RESP: 1
stim3: silence.wav
trig1.RESP:
stim5: silence.wav
trig1.RESP:
trig6.RESP: 1
stim777: silence.wav
stim111: silence.wav
trig1.RESP:
trig6.RESP: 1
trig1.RESP:
trig6.RESP: 1"""
pat = ('^(.+silence.wav.*)(?<! ) *\n'
'(?:(?!.*silence.wav)(.*)(?<! ) *\n)?'
'(?:(?!.*silence.wav)(.*)(?<! ) *)?')
RE = re.compile(pat,re.MULTILINE)
for tugr in RE.findall(ss):
print tugr
结果
('stim4: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1')
('stim5: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1')
('stim3: silence.wav', 'trig1.RESP:', '')
('stim5: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1')
('stim777: silence.wav', '', '')
('stim111: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1')
然后你用这些行元组做你想做的事
pat 是一个字符串,用作定义正则表达式的模式 RE 是一个已编译的正则表达式,它是一个具有搜索,匹配, findall 等方法的对象
括号( )
定义一个组。
一组捕获文本的某些部分。
但是(?: )
定义了一个不能捕获它匹配的文本部分的组。对文本的一部分采取行动很有用,例如将限定符*
或?
或+
放在一个组的末尾。
当第三行有'silence.wav'时,它必须保持不匹配状态,
当第二行有'silence.wav'时,只有第一行必须匹配。
这就是为什么模式中的两个位置存在(?.*silence.wav)
部分的原因。
^
是一个标志,意思是“字符串的开头”
带有^
标志的re.MULTILINE
表示“开始行”
模式的(?<! ) *
部分不会捕捉到行尾的空格。
模式中的点.
表示“任何字符”,LF字符除外
\n
还有其他一点,如果你需要我可以回答你。