diff --git a/doc/utils/converters/lammpsdoc/txt2rst.py b/doc/utils/converters/lammpsdoc/txt2rst.py
index 73c5ff91dc8cea5e037690366d534ac30c3e3984..a4196e501b665330514be404eb69a286ee125e9d 100755
--- a/doc/utils/converters/lammpsdoc/txt2rst.py
+++ b/doc/utils/converters/lammpsdoc/txt2rst.py
@@ -65,6 +65,13 @@ class RSTMarkup(Markup):
     def escape_rst_chars(self, text):
         text = text.replace('*', '\\*')
         text = text.replace('^', '\\^')
+        text = re.sub(r'([^"])_', r'\1\\_', text)
+        return text
+
+    def unescape_rst_chars(self, text):
+        text = text.replace('\\*', '*')
+        text = text.replace('\\^', '^')
+        text = text.replace('\\_', '_')
         return text
 
     def inline_math(self, text):
@@ -74,8 +81,7 @@ class RSTMarkup(Markup):
         while start_pos >= 0 and end_pos >= 0:
             original = text[start_pos:end_pos+2]
             formula = original[2:-2]
-            formula = formula.replace('\\*', '*')
-            formula = formula.replace('\\^', '^')
+            formula = self.unescape_rst_chars(formula)
             replacement = ":math:`" + formula.replace('\n', ' ').strip() + "`"
             text = text.replace(original, replacement)
 
@@ -88,6 +94,8 @@ class RSTMarkup(Markup):
         content = content.strip()
         content = content.replace('\n', ' ')
 
+        href = self.unescape_rst_chars(href)
+
         anchor_pos = href.find('#')
 
         if anchor_pos >= 0:
@@ -130,11 +138,11 @@ class RSTFormatting(Formatting):
                          link.lower().endswith('.jpeg') or
                          link.lower().endswith('.png') or
                          link.lower().endswith('.gif')):
-            converted = ".. thumbnail:: " + link + "\n"
+            converted = ".. thumbnail:: " + self.markup.unescape_rst_chars(link) + "\n"
         else:
-            converted = ".. image:: " + file + "\n"
+            converted = ".. image:: " + self.markup.unescape_rst_chars(file) + "\n"
             if link:
-                converted += "   :target: " + link + "\n"
+                converted += "   :target: " + self.markup.unescape_rst_chars(link) + "\n"
 
         if "c" in self.current_command_list:
             converted += "   :align: center\n"
@@ -303,8 +311,7 @@ class RSTFormatting(Formatting):
                 start = ""
                 body = parts[0]
 
-            body = body.replace('\\*', '*')
-            body = body.replace('\\^', '^')
+            body = self.markup.unescape_rst_chars(body)
 
             if len(start) > 0:
                 text += start + "\n"
diff --git a/doc/utils/converters/tests/test_txt2rst.py b/doc/utils/converters/tests/test_txt2rst.py
index a4b059fbf3200d2daa2d3b90af5334d1bec43226..1602fb61f9e5593c76c268bf58dee3e42a487879 100644
--- a/doc/utils/converters/tests/test_txt2rst.py
+++ b/doc/utils/converters/tests/test_txt2rst.py
@@ -85,6 +85,10 @@ class TestMarkup(unittest.TestCase):
         s = self.markup.convert("x^2")
         self.assertEqual("x\^2", s)
 
+    def test_escape_underscore(self):
+        s = self.markup.convert("x_")
+        self.assertEqual("x\_", s)
+
     def test_paragraph_with_italic(self):
         self.assertEqual("A sentence with a *italic* word", self.markup.convert("A sentence with a {italic} word"))