2008-12-11 8 views
7

Y at-il un moyen de diviser une longue chaîne de HTML après N mots? Il est évident que je pourrais utiliser:Split HTML après N mots en python

' '.join(foo.split(' ')[:n]) 

pour obtenir les premiers mots de n d'une chaîne de texte brut, mais cela pourrait diviser au milieu d'une balise html, et ne produira pas html valide car il ne fermera pas la tags qui ont été ouverts.

Je dois le faire sur un site zope/plone - s'il y a quelque chose de standard dans les produits qui peuvent le faire, ce serait idéal.

Par exemple, dire que j'ai le texte:

<p>This is some text with a 
    <a href="http://www.example.com/" title="Example link"> 
    bit of linked text in it 
    </a>. 
</p> 

et je demande à diviser après 5 mots, il doit retourner:

<p>This is some text with</p> 

7 mots:

<p>This is some text with a 
    <a href="http://www.example.com/" title="Example link"> 
    bit 
    </a> 
</p> 
+0

Voulez-vous ignorer les balises afin qu'elles ne soient pas divisées? En d'autres termes, n'obtenez et ne divisez que du texte qui n'est pas contenu dans une balise. – monkut

+0

Cherchez-vous à scinder du texte de document encapsulé entre des balises (par exemple, entre les balises

et

)? – gotgenes

Répondre

6

Regardez la fonction truncate_html_words dans django.utils.text. Même si vous n'utilisez pas Django, le code fait exactement ce que vous voulez.

3

J'ai entendu dire que Beautiful Soup est très bon pour analyser le HTML. Il sera probablement en mesure de vous aider à obtenir html correct.

0

J'allais mentionner la base HTMLParser qui est construite en Python, car je ne suis pas sûr du résultat final que vous essayez d'obtenir, il peut ou peut ne pas vous y arriver, vous travaillerez avec le

0

Vous pouvez utiliser un mélange de regex, BeautifulSoup ou Tidy (je préfère BeautifulSoup). L'idée est simple - dépouiller d'abord toutes les balises HTML. Trouvez le nième mot (n = 7 ici), trouvez le nombre de fois où le nième mot apparaît dans la chaîne jusqu'à n mots - coz u ne cherchez que la dernière occurrence à utiliser pour la troncature.

Voici un morceau de code, mais un peu compliqué, mais fonctionne

import re 
from BeautifulSoup import BeautifulSoup 
import tidy 

def remove_html_tags(data): 
    p = re.compile(r'<.*?>') 
    return p.sub('', data) 

input_string='<p>This is some text with a <a href="http://www.example.com/" '\ 
    'title="Example link">bit of linked text in it</a></p>' 

s=remove_html_tags(input_string).split(' ')[:7] 

###required to ensure that only the last occurrence of the nth word is                      
# taken into account for truncating.                              
# coz if the nth word could be 'a'/'and'/'is'....etc                          
# which may occur multiple times within n words                            
temp=input_string 
k=s.count(s[-1]) 
i=1 
j=0 
while i<=k: 
    j+=temp.find(s[-1]) 
    temp=temp[j+len(s[-1]):] 
    i+=1 
####                                       
output_string=input_string[:j+len(s[-1])] 

print "\nBeautifulSoup\n", BeautifulSoup(output_string) 
print "\nTidy\n", tidy.parseString(output_string) 

La sortie est ce que tu veux

BeautifulSoup 
<p>This is some text with a <a href="http://www.example.com/" title="Example link">bit</a></p> 

Tidy 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"> 
<html> 
<head> 
<meta name="generator" content= 
"HTML Tidy for Linux/x86 (vers 6 November 2007), see www.w3.org"> 
<title></title> 
</head> 
<body> 
<p>This is some text with a <a href="http://www.example.com/" 
title="Example link">bit</a></p> 
</body> 
</html> 

Hope this helps

Edit: Une meilleure regex

`p = re.compile(r'<[^<]*?>')` 
+0

Une raison pour laquelle vous écrivez votre propre fonction pour supprimer les balises HTML et ne pas utiliser de soupe de Beauitful [soup.get_text()] (http://www.crummy.com/software/BeautifulSoup/bs4/doc/#get-text) méthode? – tatlar