我有一组文件,我在其中标记了段落和句子的开头,但我需要迭代每个文件,以便文件中的每个段落和每个句子都有唯一的数字ID。我相信这可以使用str.replace或使用正则表达式模块来完成。
在外部文件中,句子开头标记标记如下:
<p id="####"> # 4 for paragraphs
<s id="#####"> # 5 for sentences
所以在这里我做了调用外部文件并调用段落和句子编号功能(在单独的模块中)的工作,这不起作用。
import re, fileinput, NumberRoutines
ListFiles = ['j2vch34.txt', '79HOch16.txt']
with fileinput.input(files=(ListFiles), inplace=True, backup='.bak') as f:
for filename in ListFiles:
with open(filename) as file:
text = file.read() # read file into memory
text = NumberRoutines.NumberParas(text)
text = NumberRoutines.NumberSentences(text)
with open(filename, 'w') as file:
file.write(text)
在NumberRoutines中,我尝试应用编号,这是段落的例子:
def NumberParas(text):
sub = "p id="
str = text
totalparas = str.count(sub, 0, len(str))
counter = 0
for paranumber in range(totalparas):
return str.replace('p id="####"', 'p id="{paranumber}"'.format(**locals()))
counter += 1
根据R Nar的回复,我已经修复了之前的问题,以便我不再收到错误。它重写文件,但是paranumber总是为0。
我尝试应用编号的第二种方式,这次用句子:
def NumberSentences(text):
sub = "s id="
str = text
totalsentences = str.count(sub, 0, len(str))
counter = 0
for sentencenumber in range(totalsentences):
return str.replace('s id="#####"', 's id="{counter}"'.format(**locals()))
counter += 1
前类型错误(无法将'int'对象隐式转换为str)已解决。
它正在读取和重写文件,但所有句子都被编号为0。
另外两个问题: 1.我是否需要**本地用于for语句中的变量的本地范围? 2.这可以用RegEx完成吗?尽管有很多尝试,但我无法使用{}来替换变量值以使用正则表达式。
我已阅读https://docs.python.org/3.4/library/stdtypes.html#textseq以及Python 3中Mark Summerfields Programming的第13章,并受到Dan McDougall对Putting a variable inside a string (python)的回答的影响
几年前,我在PERL中遇到了同样的事情,2009 Query to PERL beginners,所以感叹。
答案 0 :(得分:1)
我不知道为什么你有inputfile
行,如果你已经要遍历with块内的每个文件,那么我就把它拿出去了
for filename in ListFiles:
with open(filename) as file:
text = file.read()
text = NumberRoutines.NumberParas(text)
text = NumberRoutines.NumberSentences(text)
with open(filename, 'w') as file:
file.write(text) # produces error on this line
这使用相同的逻辑。但是,使用您的代码,您的写入块不在for循环中,然后只会写入文件列表中的最后一个文件。
现在有了这些功能:
def NumberParas(text):
#all that starting stuff can be eliminated with the for loop below
returnstring = ''
for i, para in enumerate(text.split('p id="####"')): # minor edit to match spacing in sample.
if i:
returnstring = returnstring + 'p id = "%d"%s' % (i-1,para)
else:
returnstring = para
return returnstring
并且类似地:
def NumberSentences(text):
returnstring = ''
for i, sent in enumerate(text.split('s id="#####"')): # minor edit to match spacing.
if i:
returnstring = returnstring + 's id = "%d"%s' % (i-1,sent) # minor edit for "sent" in this isntance
else:
returnstring = sent
return returnstring
我改变逻辑的原因是因为str.replace
替换了你想要替换的所有实例,而不仅仅是第一个。这意味着第一次调用它时,所有标签都将在文本中被替换,而for循环的其余部分则无用。另外,你需要实际返回字符串,而不是仅仅在函数中更改它,因为字符串是不可变的,因此你在函数内部的字符串不是你想要改变的真正字符串。
内部if i:
行是因为枚举列表中的第一项是第一个标记之前的内容。我认为这将是空的,因为标签在每个句子/段落之前,但你可能有空格或
顺便说一下:这可以通过单线程完成,因为python:
>>> s = 'p tag asdfawegasdf p tag haerghasdngjh p tag aergaedrg'
>>> ''.join(['p tag%d%s' % (i-1, p) if i else p for i,p in enumerate(s.split('p tag'))])
'p tag0 asdfawegasdf p tag1 haerghasdngjh p tag2 aergaedrg'
答案 1 :(得分:1)
TypeError:必须是str,而不是None
您的NumberParas(text)
不返回任何内容
TypeError:无法将'int'对象隐式转换为str
使用int i
str
转换为str(i)
- 我是否需要**本地用于for语句中的变量的本地范围?
醇>
您需要locals
() 函数调用来自动构建参数dict。
- 这可以用RegEx完成吗?尽管尝试了很多次,但我无法使用{}来替换变量值以使用正则表达式
醇>
#!/usr/bin/env python3
import re
tok='####'
regex = re.compile(tok)
bar = 41
def foo(s):
bar = 42
return regex.sub("%(bar)i" % locals(), s)
s = 's id="####"'
print(foo(s))
输出:
s id="42"