# -*- coding: UTF-8 -*-
import re
import itertools
targ = ['\t- Task 09', '\tThis is a comment', '\t\t- Subtask 9.02', '\t\t\t- Subsubtask 9.03', '\t\t\t\t- Subsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.02', '\t\t\t\t\t- Subsubsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.03 @done', '\t\t\t- Subsubtask 9.04', '\t\t\t\t- Subsubsubtask 9.19 @done']
def DoneChild2Parent(l):
tasks = [(k,v) for k,v in enumerate(l) if re.search('\t+-\s.*',v)]
for x,y in tasks:
if (x,y) == tasks[len(tasks[1:])]:
print (x,y), '==', tasks[len(tasks[1:])]
return l #Also tried break here.
elif re.search('(?!.*@done)\t*-\s.*', y):
next_task = tasks[tasks.index((x,y))+1]
if next_task[1].count('\t') > y.count('\t'):
subtasks = list(itertools.takewhile(lambda t: t.count('\t') > y.count('\t'), [z for w,z in tasks[tasks.index(next_task):]]))
if all('@done' in subtask for subtask in subtasks):
l[x]+=' @done'
DoneChild2Parent(l)
# return l #when using break above
print DoneChild2Parent(targ)
匹配列表的最新元素时,应返回此函数。现在它只是循环。它标识何时(x,y) == tasks[len(tasks[1:])]:
,但是返回和中断都不会让我退出循环。
这是代码的更简化版本。在保持问题的同时,我将论点缩小到尽可能小:
# -*- coding: UTF-8 -*-
import re
targ = ['\t- Task 09', '\tThis is a comment', '\t\t- Subtask 9.02', '\t\t\t- Subsubtask 9.03', '\t\t\t\t- Subsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.02', '\t\t\t\t\t- Subsubsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.03 @done', '\t\t\t- Subsubtask 9.04', '\t\t\t\t- Subsubsubtask 9.19 @done']
def DoneChild2Parent(l):
tasks = iter([(x,y) for x,y in enumerate(l) if re.search('\t+-\s.*',y)])
for k in tasks:
if re.search('(?!.*@done)\t*-\s.*', k[1]):
nt = tasks.next()
if nt[1].count('\t') > k[1].count('\t'):
subtasks = [subtask for subtask in l[k[0]:] if subtask.count('\t') > k[1].count('\t') and re.search('\t+-\s.*',subtask) ]
if all('@done' in subtask for subtask in subtasks):
l[k[0]]+=' @done'
DoneChild2Parent(l)
return l
print DoneChild2Parent(targ)
关于@abarnert问题:我需要“下一个任务”来比较它与所讨论任务之间的“\ t”数量。如果下一个任务比任务具有更多'\ t',则意味着下一个任务是任务的子任务。如果 task 的所有子项都标有“@done”,则还应标记 task 。我过滤整个输入以避免注释(根据语法),这会破坏代码。我还保留原始列表中的索引,然后添加'@done'标记。我希望这段代码能够顺利运行给大家。感谢您的光临和阅读这段文字(:
# -*- coding: UTF-8 -*-
import re
import itertools
targ = ['\t- Task 09', '\tThis is a comment', '\t\t- Subtask 9.02', '\t\t\t- Subsubtask 9.03', '\t\t\t\t- Subsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.02', '\t\t\t\t\t- Subsubsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.03 @done', '\t\t\t- Subsubtask 9.04', '\t\t\t\t- Subsubsubtask 9.19 @done']
def DoneChild2Parent(l):
tasks = [(k,v) for k,v in enumerate(l) if re.search('\t+-\s.*',v)]
for x,y in tasks[:-1]:
if re.search('(?!.*@done)\t*-\s.*', y):
next_task = tasks[tasks.index((x,y))+1]
if next_task[1].count('\t') > y.count('\t'):
subtasks = list(itertools.takewhile(lambda t: t.count('\t') > y.count('\t'), [z for w,z in tasks[tasks.index(next_task):]]))
if all('@done' in subtask for subtask in subtasks):
l[x]+=' @done'
DoneChild2Parent(l)
return l
print DoneChild2Parent(targ)
为公开标题道歉,最重要的是要求您确定问题,而不是仅仅建议已找到问题的解决方案。下面的代码是我正在使用的代码的简化版本,我删除了一些无用的函数,但结果是一样的。控制台上的打印结果将指导我们完成我的问题:
# -*- coding: UTF-8 -*-
import re
import itertools
targ = '\t- Task 09\n\tThis is a comment\n\t\t- Subtask 9.01 @done\n\t\tThis is a subtask comment\n\t\t- Subtask 9.02\n\t\tAnother comment\n\t\t\t- Subsubtask 9.01 @done\n\t\t\t- Subsubtask 9.02 @done\n\t\t\tWhy so many comments?\n\t\t\t- Subsubtask 9.03\n\t\t\t\t- Subsubsubtask 9.01 @done\n\t\t\t\tJust another comment to break your code\n\t\t\t\t- Subsubsubtask 9.02\n\t\t\t\tBreak, break, break\n\t\t\t\t\t- Subsubsubsubtask 9.01 @done\n\t\t\t\t\tThis is the last comment, I promise\n\t\t\t\t- Subsubsubtask 9.03 @done\n\t\t\t\tI lied.\n\t\t\t- This is the task of interest\n\t\t\t\t- Subsubsubtask 9.03 @done\n\t\t\t\tI love lying\n\t\t\t- Subsubtask 9.05 @done\n\t\t- Subtask 9.03 @done\n\t\tOk, this is truly the last comment.\n\t\tNah.'
regex = re.split('\n(?=^\t-\s)', targ, 0, re.M)
c = 0
def DoneChild2Parent(l):
global c
c+=1
tasks = iter([(x,y) for x,y in enumerate(l) if re.search('\t+-\s.*',y)])
print "=================\n==:: ROUND %s ::==\n================="%(c)
for k in tasks:
print "* Step 1: %s => This is the task being checked:" %(str(k))
if re.search('(?!.*@done)\t*-\s.*', k[1]):
print "* Step 2: %s => Was not done so we check the next task/subtasks" %(str(k))
nt = tasks.next()
if nt[1].count('\t') > k[1].count('\t'):
print "* Step 3: %s => is the next subtask" %(str(nt))
subtasks = [subtask for subtask in l[k[0]:] if subtask.count('\t') > k[1].count('\t') and re.search('\t+-\s.*',subtask) ]
print "* Length of subtasks is",len(subtasks)
print "* Step 4: Subtasks for %s\n" %(k[0]),subtasks
if all('@done' in subtask for subtask in subtasks):
print "\n* Step 5: Adding @done to %s at index %s" %(k[1].strip(), k[0])
print "Before: ",l[k[0]]
l[k[0]]+=' @done'
print "After: ",l[k[0]],"\n---------------------\n"
DoneChild2Parent(l)
else:
print "\n* Step 5: Not everything is done yet\n---------------------\n"
return l
for task in regex:
itask = task.split('\n')
DoneChild2Parent(itask)
该字符串是使用TaskPaper语法的任务列表,TaskPaper是Mac的任务管理器,使用纯文本文件。任务以' - '开头,项目以':'结尾(在此示例中不存在),评论既不是。缩进定义任务和注释之间的层次结构。当任务标记为已完成时,它会获得一个标记'@done'(每个标记都以@开头)。对于这个例子,我使用的是单个多层次的任务。如果有多个主要任务(当项目是直接父项时),那么最终的正则表达式和for循环是存在的。
该函数循环遍历列表中的每个任务,检查它是否被撤消并包含子任务。然后,它收集所有子任务并检查它们是否都标记为@done,如果是,它也将父任务标记为@done。
当你运行这个脚本时,你会发现这个目的是有效的,但是循环的进行比预期更多并且采取了一个奇怪的方向。我将问题发生的任务命名为“这是感兴趣的任务”,因此您可以在打印时轻松识别它。
感兴趣的任务在脚本的第3轮中被正确标记为@done。脚本继续循环,直到它标记第5轮中的主要任务,这意味着每个子任务都标记为@done(列表是在构建时考虑到的)。现在,请看看第6轮。它应该是最新的循环,其中函数将检查没有什么可做并返回值,但是,您可能会注意到以下几行:
* Step 1: (22, '\t\t- Subtask 9.03 @done') => This is the task being checked:
* Step 1: (4, '\t\t- Subtask 9.02 @done') => This is the task being checked:
它检查最后一个任务并循环回到开始。我不知道为什么它会循环回到第二个任务。此行为重复,并且开始重新循环的任务始终不同。我想知道为什么会这样。但最糟糕的是,你会注意到,在给定的时刻,脚本会找到“感兴趣的任务”,我们之前标记为@done的那个,撤消并再次操作循环。结果是'感兴趣的任务'最终附加了3个@done标签:
After: - This is the task of interest @done @done @done
我正在寻找的结果是第6轮第8轮。感谢您的关注,我很抱歉这么长的文字。
答案 0 :(得分:1)
我首先要问你希望这个正则表达式匹配的是什么:
if re.search('(?!.*@done)\t*-\s.*', k[1]):
用言语解释你的意图?例如,您是否对此字符串匹配感到惊讶:
"abc @done- def"
?您是否意识到该正则表达式中的尾随.*
没有任何意义(正则表达式与是否匹配相同的字符串)?
我不知道这是否与你的问题有关;-)但是我的生活中已经看到了很多正则表达式,我无法猜出你希望这个会做什么。我最好的猜测是,你希望它匹配\t*-\s
并不紧跟@done
之前 - 但在这种情况下,你需要在*断言之后看到负面看法。
答案 1 :(得分:1)
感谢您的帮助。 This StackOverflow thread给了我很多帮助。我只需要在正确的位置放置一个break
:
# -*- coding: UTF-8 -*-
import re
import itertools
targ = ['\t- Task 09', '\tThis is a comment', '\t\t- Subtask 9.02', '\t\t\t- Subsubtask 9.03', '\t\t\t\t- Subsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.02', '\t\t\t\t\t- Subsubsubsubtask 9.01 @done', '\t\t\t\t- Subsubsubtask 9.03 @done', '\t\t\t- Subsubtask 9.04', '\t\t\t\t- Subsubsubtask 9.19 @done']
def DoneChild2Parent(l):
tasks = [(k,v) for k,v in enumerate(l) if re.search('\t+-\s.*',v)]
for x,y in tasks:
if re.search('(?!.*@done)\t*-\s.*', y):
next_task = tasks[tasks.index((x,y))+1]
if next_task[1].count('\t') > y.count('\t'):
subtasks = list(itertools.takewhile(lambda t: t.count('\t') > y.count('\t'), [z for w,z in tasks[tasks.index(next_task):]]))
if all('@done' in subtask for subtask in subtasks):
l[x]+=' @done'
DoneChild2Parent(l)
break
return l
print DoneChild2Parent(targ)
为什么会这样?很简单,循环会调用函数,但它不会结束。因此,当最后一个循环调用no函数并结束时,它会将结果返回到前一个函数并继续循环,这将发现先前任务中已修复的其他问题并再次调用该函数,生成您看到的混乱(: