选择文本文档的多行并在python中写入新文本doc时出现问题

时间:2012-11-30 20:54:37

标签: python

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,但是由于我描述的原因,我的输出没有显示出来。 有没有办法可以让它不跳过那个刺激?

对不起,如果这真的很长。提前谢谢!

4 个答案:

答案 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

还有其他一点,如果你需要我可以回答你。