Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turning multiple different hashtags to links with python

Tags:

python

sql

bottle

Currently working on a web server with bottle and trying to implement a function that accepts a message and converts it to HTML suitable for display. There is the limitation of

Any hashtags in the text ('#' followed by a sequence of letters, numbers or periods)
are enclosed by a <strong class='hashtag'> tag. 
Eg. <strong class='hashtag'>#whatever</strong>

The part i have an issue with is when there is more than one hashtag in a block of text, as using regex allows me to find the certain hashtag blocks but re.sub replaces all hashtags with the one value given. This is what i have:

def post_to_html(content):
    if (re.search(r'#[\d\w\.]*', content) is not None):
    hold = re.search(r'#[\d\w\.]*', content).group(0)
    repltxt = "<strong class='hashtag'>{0}</strong>".format(hold)
    hold = re.sub(r'#[\d\w\.]*', repltxt, content)
    content = hold

Which when given:

"#whatever you #want"

Outputs:

<strong class='hashtag'>#whatever</strong> you <strong class='hashtag'>#whatever</strong>

1 Answers

You can actually fix your problem with only one usage of the re.sub method and then you don't have to hold any variables and so on:

fixed_content = re.sub(r"(#[\d\w\.]+)", r"<strong class='hashtag'>\1</strong>", content)

You do need to change your regex a bit:

  1. use the + instead of the * to make sure you don't match any lonely # in the content
  2. add brackets around the hashtag matching part to create a capturing group for backreferencing afterwards with \g<1> or \1.

The \g<n> and \n are what we call "backreferences" in the regular expressions world. You can have multiple capturing groups and multiple backreferences as well - \1, \2, \n. According to this definition:

Backreferences match the same text as previously matched by a capturing group

You can use backreferences every time you need to reuse its capturing group's matched content. In your case, you want to save the actual hashtag for later usage, so instead of having additional temp variables, you can just use the backreference \n.

Have a look at a simple example. Let's say you want a regex to replace HTML <strong> tags with <b> and you come up with the following regex:

> pattern = re.compile(r"<strong>.+?</strong>")

This will match everything between a <strong> and </strong>, tags included. However, you want to reuse the actual element in between those tags. So let's make a capturing group by surrounding the element matching part with brackets:

> pattern = re.compile(r"<strong>(.+?)</strong>")

Now, your capturing group's content can be reused with \1. If we try to use it with an example text this is what happens:

> pattern.sub(r"<b>\1</b>", "some <strong>text</strong> example")
'some <b>text</b> example'

Backreferences are super useful when dealing with replacements and complex regexes. You can read a bit more about them here and also check Python's documentation on how to use it in a more advanced way.

like image 54
Pedro Pregueiro Avatar answered Sep 10 '26 18:09

Pedro Pregueiro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!