Bien que je sache que je pourrais utiliser certaines expressions rationnelles hugeass telles que celle publiée ici je me demande s’il existe une façon très fictive de le faire avec un module standard ou peut-être un complément tiers?
Question simple, mais rien n'a sauté sur Google (ou Stackoverflow).
J'ai hâte de voir comment vous allez faire ça!
Utilisez une expression régulière.
Réponse au commentaire de l'OP: Je sais que ce n'est pas utile. Je vous dis la bonne façon de résoudre le problème car vous avez dit que c'était d'utiliser une expression régulière.
Regardez l'approche de Django ici: Django.utils.urlize()
. Les expressions régulières sont trop limitées pour le travail et vous devez utiliser des méthodes heuristiques pour obtenir des résultats généralement corrects.
Je sais que c'est exactement ce que vous ne voulez pas mais voici un fichier avec un regex énorme:
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
the web url matching regex used by markdown
http://daringfireball.net/2010/07/improved_regex_for_matching_urls
https://Gist.github.com/gruber/8891611
"""
URL_REGEX = r"""(?i)\b((?:https?:(?:/{1,3}|[a-z0-9%])|[a-z0-9.\-]+[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|Gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)/)(?:[^\s()<>{}\[\]]+|\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\))+(?:\([^\s()]*?\([^\s()]+\)[^\s()]*?\)|\([^\s]+?\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:(?<!@)[a-z0-9]+(?:[.\-][a-z0-9]+)*[.](?:com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|Gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)\b/?(?!@)))"""
J'appelle ce fichier urlmarker.py
et quand j'en ai besoin, je l'importe simplement, par exemple.
import urlmarker
import re
re.findall(urlmarker.URL_REGEX,'some text news.yahoo.com more text')
cf. http://daringfireball.net/2010/07/improved_regex_for_matching_urls
Aussi, voici ce que Django (1.6) utilise pour valider URLField
s:
regex = re.compile(
r'^(?:http|ftp)s?://' # http:// or https://
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
r'localhost|' # localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
r'(?::\d+)?' # optional port
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
cf. https://github.com/Django/django/blob/1.6/Django/core/validators.py#L43-50
Django 1.9 a cette logique divisée en quelques classes
... qui peut être trouvé à cette page: À la recherche de la regex de validation d'URL parfaite .
La regex de Diego Perini, qui a passé tous les tests, est very long mais est disponible sur son Gist ici .
Notez que vous devrez convertir sa version PHP en regex python (il existe de légères différences).
J'ai fini par utiliser la version Imme Emosol qui passe la grande majorité des tests et représente une fraction de la taille de celle de Diego Perini.
Voici une version compatible avec Python de l'expression régulière Imme Emosol:
r'^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$'
Vous pouvez utiliser cette bibliothèque, j'ai écrit:
https://github.com/imranghory/urlextractor
C'est extrêmement difficile, mais il ne s'appuie pas sur "http: //" comme beaucoup d'autres techniques, mais utilise la liste des TLD de Mozilla (via la bibliothèque tldextract) pour rechercher des TLD (c'est-à-dire ".co.uk", "." com ", etc.) dans le texte et tente ensuite de construire des URL autour du TLD.
Il ne vise pas à être conforme aux RFC, mais à préciser la manière dont les URL sont utilisées dans la pratique. Ainsi, par exemple, il rejettera le domaine techniquement valide "com" (vous pouvez en fait utiliser un TLD comme domaine; bien que ce soit rare dans la pratique) et effacera les balises de fond ou les virgules.
si vous savez qu'il y a une URL après un espace dans la chaîne, vous pouvez faire quelque chose comme ceci:
s est la chaîne contenant l'url
>>> t = s[s.find("http://"):]
>>> t = t[:t.find(" ")]
sinon, vous devez vérifier si find renvoie -1 ou non.
Vous pouvez utiliser BeautifulSoup .
def extractlinks(html):
soup = BeautifulSoup(html)
anchors = soup.findAll('a')
links = []
for a in anchors:
links.append(a['href'])
return links
Notez que la solution avec les expressions rationnelles est plus rapide, mais ne sera pas aussi précise.
Je suis en retard à la soirée, mais voici une solution qui m'a été suggérée par quelqu'un de #python on freenode. Cela évite les tracas de regex.
from urlparse import urlparse
def extract_urls(text):
"""Return a list of urls from a text string."""
out = []
for Word in text.split(' '):
thing = urlparse(Word.strip())
if thing.scheme:
out.append(Word)
return out
import re
text = '<p>Please click <a href="http://www.dr-chuck.com">here</a></p>'
aa=re.findall('href="(.+)"',text)
print(aa)
Il existe un autre moyen d'extraire facilement les URL du texte. Vous pouvez utiliser urlextract pour le faire pour vous, installez-le simplement via pip:
pip install urlextract
et ensuite vous pouvez l'utiliser comme ceci:
from urlextract import URLExtract
extractor = URLExtract()
urls = extractor.find_urls("Let's have URL stackoverflow.com as an example.")
print(urls) # prints: ['stackoverflow.com']
Vous pouvez trouver plus d’informations sur ma page github: https://github.com/lipoja/URLExtract
NOTE: Il télécharge la liste des TLD de iana.org pour vous tenir au courant. Mais si le programme n'a pas accès à Internet, alors ce n'est pas pour vous.
Cette approche est similaire à celle utilisée dans urlextractor (mentionné ci-dessus), mais mon code est récent, maintenu et je suis ouvert à toute suggestion (nouvelles fonctionnalités).