将选项卡式文本转换为html无序列表?

时间:2012-08-28 16:53:38

标签: python html

我是初学程序员,所以这个问题可能听起来微不足道:我有一些文本文件包含制表符分隔的文本,如:

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]

4 个答案:

答案 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.bufferencoding="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>&lt;ul&gt;: '+str(n1)+'<br>&lt;&frasl;ul&gt;: '+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>