question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Hello! I would like to know if it is possible to add an hyperlink to an existing portion of text. I have read the helper functions provided in past issues, but I did not find something helpful for me.

That’s the question: I have some text, for example, My name is Roberto and I am a lawyer (doc. 1) I would like to add an hyperlink to the string “doc. 1” (in the same way i may set an hyperlink in a word processor, just underlining text).

I have read the docs and it seems that hyperlink may be managed at Runs level. The problem is that i have not understood if I can set a Run inside an existing paragraph (without adding a new one).

# coding=utf-8

import docx
import hyperlink
import helpers

doc = docx.Document('atto.docx')

paragraphs = doc.paragraphs

txt = 'doc. 1'

for p in paragraphs:
    runs = p.runs

    for run in runs:
        print run.text
        if txt in run.text:
            hyperlink.add(p, run, 'https://github.com')
            run.font.color.rgb = docx.shared.RGBColor(0, 0, 255)
            

doc.save('new-atto.docx')

I tried this code (using the hyperlink function created by someone here, which adds the link to an existing run) but it does not work very well. I tried to set in the word processor “doc. 1” in bold (in order to assume that “doc.1” will be considered as a distinct run) but the implementation is quite buggy.

Could you please give me some advice ? (I am a lawyer and still inexperienced as developer 😃 )

@EDIT: if i change some styling in the string “doc. 1” in the original document, the above-mentioned will become a separate Run and the above code may work.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

4reactions
braskycommented, Feb 4, 2020

Here’s some code I threw together which will find some pattern in a run and replace it with a new run with the pattern text and then add the hyperlink to it. As far as I know there’s no way through the docx api to add a run after or before a given run, but through this post by @scanny I found the solution through lxml.etree._Element.

By the way, in the future I think the recommended forum for help is Stack Overflow using the “python-docx” tag.

import re
import docx
from docx.text.run import Run

# --- this document contains one paragraph and one run with the following text:
# --- "Please refer to document 1 (doc. 1). More testing sentences. "
doc = docx.Document('testing runs.docx')

# --- This is the pattern to match the string '(doc. #)'
pattern = "\(doc. [0-9]\)."

def add_hyperlink_into_run(paragraph, run, url):
    runs = paragraph.runs
    for i in range(len(runs)):
        if runs[i].text == run.text:
            break
    # --- This gets access to the document.xml.rels file and gets a new relation id value ---
    part = paragraph.part
    r_id = part.relate_to(
        url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, is_external=True
    )
    # --- Create the w:hyperlink tag and add needed values ---
    hyperlink = docx.oxml.shared.OxmlElement('w:hyperlink')
    hyperlink.set(docx.oxml.shared.qn('r:id'), r_id, )
    hyperlink.append(run._r)
    paragraph._p.insert(i,hyperlink)
    run.font.color.rgb = docx.shared.RGBColor(0, 0, 255)

for paragraph in doc.paragraphs:
    for run in paragraph.runs:
        matches = re.findall(pattern, run.text)
        if matches:
            print("Found a match!")
            # --- this replaces the pattern we wrote above with nothing.
            run.text = re.sub(pattern, "", run.text) 
            # --- if there are more than one instances of '(doc. #)' in the run,
            # --- we want to replace all of them. This logic might not work perfectly
            # --- but it's a start.
            for match in matches: 
                new_run_element = paragraph._element._new_r()
                run._element.addnext(new_run_element)
                new_run = Run(new_run_element, run._parent)
                new_run.text = match + " "
                add_hyperlink_into_run(paragraph, new_run, "http://google.com")
                
doc.save('testing-runs-complete.docx')

Edit: There’s some goofiness with some periods being in different runs, so you might have to play with the pattern and how you edit the original text of the run. Sorry this isn’t more comprehensive, something I just threw together quickly. If you need more help I’d recommend making a stack overflow post and posting a link to it here.

1reaction
cparmetcommented, Feb 4, 2020

@brasky The add_hyperlink_into_run function was extremely helpful to me for another use case. Thanks very much!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Hyperlink - Wikipedia
In computing, a hyperlink, or simply a link, is a digital reference to data that the user can follow or be guided by...
Read more >
Create or edit a hyperlink - Microsoft Support
Create a hyperlink to a location on the web · Select the text or picture that you want to display as a hyperlink....
Read more >
What is a Hyperlink? - Computer Hope
Alternatively known as a link and web link, a hyperlink is an icon, graphic, or text that links to another file or object....
Read more >
HTML Links Hyperlinks - W3Schools
HTML links are hyperlinks. You can click on a link and jump to another document. When you move the mouse over a link,...
Read more >
What are hyperlinks? - Learn web development | MDN
A link from someone else's webpage to your site. It's the opposite of an external link. Note that you don't have to link...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found