我是初学程序员,所以这个问题可能听起来微不足道:我有一些文本文件包含制表符分隔的文本,如:
A
B
C
D
E
现在我想生成无序的.html列表,其结构为:
<ul>
<li>A
<ul><li>B</li>
<li>C
<ul><li>D</li>
<li>E</li></ul></li></ul></li>
</ul>
我的想法是编写一个Python脚本,但如果有一种更简单(自动)的方式,那也没关系。为了识别缩进级别和项目名称,我将尝试使用此代码:
import sys
indent = 0
last = []
for line in sys.stdin:
count = 0
while line.startswith("\t"):
count += 1
line = line[1:]
if count > indent:
indent += 1
last.append(last[-1])
elif count < indent:
indent -= 1
last = last[:-1]
答案 0 :(得分:5)
试试这个(适用于您的测试用例):
import itertools
def listify(filepath):
depth = 0
print "<ul>"*(depth+1)
for line in open(filepath):
line = line.rstrip()
newDepth = sum(1 for i in itertools.takewhile(lambda c: c=='\t', line))
if newDepth > depth:
print "<ul>"*(newDepth-depth)
elif depth > newDepth:
print "</ul>"*(depth-newDepth)
print "<li>%s</li>" %(line.strip())
depth = newDepth
print "</ul>"*(depth+1)
希望这有帮助
答案 1 :(得分:2)
tokenize
module了解您的输入格式:行包含有效的Python标识符,语句的缩进级别很重要。 ElementTree
module允许您在内存中操作树结构,因此将树创建与将其呈现为html可能更灵活:
from tokenize import NAME, INDENT, DEDENT, ENDMARKER, NEWLINE, generate_tokens
from xml.etree import ElementTree as etree
def parse(file, TreeBuilder=etree.TreeBuilder):
tb = TreeBuilder()
tb.start('ul', {})
for type_, text, start, end, line in generate_tokens(file.readline):
if type_ == NAME: # convert name to <li> item
tb.start('li', {})
tb.data(text)
tb.end('li')
elif type_ == NEWLINE:
continue
elif type_ == INDENT: # start <ul>
tb.start('ul', {})
elif type_ == DEDENT: # end </ul>
tb.end('ul')
elif type_ == ENDMARKER: # done
tb.end('ul') # end parent list
break
else: # unexpected token
assert 0, (type_, text, start, end, line)
return tb.close() # return root element
任何提供.start()
,.end()
,.data()
,.close()
方法的类都可以用作TreeBuilder
,例如,您可以在飞而不是建树。
要解析stdin并将html写入stdout,您可以使用ElementTree.write()
:
import sys
etree.ElementTree(parse(sys.stdin)).write(sys.stdout, method='html')
输出:
<ul><li>A</li><ul><li>B</li><li>C</li><ul><li>D</li><li>E</li></ul></ul></ul>
您可以使用任何文件,而不只是sys.stdin/sys.stdout
。
注意:要在Python 3上写入stdout,请使用sys.stdout.buffer
或encoding="unicode"
,因为字节/ Unicode区别。
答案 2 :(得分:0)
我认为算法是这样的:
跟踪当前缩进级别(通过计算每行的标签数量)
如果缩进级别增加:发出<ul> <li>current item</li>
如果缩进级别降低:发出<li>current item</li></ul>
如果缩进级别保持不变:发出<li>current item</li>
将此代码放入OP作为练习
答案 3 :(得分:-1)
算法很简单。您可以获取用tab \ t指示的行的深度级别,并将下一个项目移动到右侧\ t + \ t或向左移动\ t \ t- \ t或将其保持在同一级别\ t。
确保您的&#34; in.txt&#34;如果从此处复制,则包含制表符或用制表符替换缩进。如果缩进是由空格组成的,则无效。而分隔符最后是一个空行。如果需要,您可以在代码中更改它。
J.F。塞巴斯蒂安的解决方案很好,但没有处理unicode。
创建一个文本文件&#34; in.txt&#34;采用UTF-8编码:
qqq
www
www
яяя
яяя
ыыы
ыыы
qqq
qqq
并运行脚本&#34; ul.py&#34;。该脚本将创建&#34; out.html&#34;并在Firefox中打开它。
#!/usr/bin/python
# -*- coding: utf-8 -*-
# The script exports a tabbed list from string into a HTML unordered list.
import io, subprocess, sys
f=io.open('in.txt', 'r', encoding='utf8')
s=f.read()
f.close()
#---------------------------------------------
def ul(s):
L=s.split('\n\n')
s='<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n\
<html><head><meta content="text/html; charset=UTF-8" http-equiv="content-type"><title>List Out</title></head><body>'
for p in L:
e=''
if p.find('\t') != -1:
l=p.split('\n')
depth=0
e='<ul>'
i=0
for line in l:
if len(line) >0:
a=line.split('\t')
d=len(a)-1
if depth==d:
e=e+'<li>'+line+'</li>'
elif depth < d:
i=i+1
e=e+'<ul><li>'+line+'</li>'
depth=d
elif depth > d:
e=e+'</ul>'*(depth-d)+'<li>'+line+'</li>'
depth=d
i=depth
e=e+'</ul>'*i+'</ul>'
p=e.replace('\t','')
l=e.split('<ul>')
n1= len(l)-1
l=e.split('</ul>')
n2= len(l)-1
if n1 != n2:
msg='<div style="color: red;">Wrong bullets position.<br><ul>: '+str(n1)+'<br><⁄ul>: '+str(n2)+'<br> Correct your source.</div>'
p=p+msg
s=s+p+'\n\n'
return s
#-------------------------------------
def detach(cmd):
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
sys.exit()
s=ul(s)
f=io.open('out.html', 'w', encoding='utf8')
s=f.write(s)
f.close()
cmd='firefox out.html'
detach(cmd)
HTML将是:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head><meta content="text/html; charset=UTF-8" http-equiv="content-type"><title>List Out</title></head><body><ul><li>qqq</li><ul><li>www</li><li>www</li><ul><li>яяя</li><li>яяя</li></ul><li>ыыы</li><li>ыыы</li></ul><li>qqq</li><li>qqq</li></ul>