Repository: spyder-ide/spyder

Issue:
"Replace selection" adds "\." anytime the string to be added contains "."
## Description of your problem

**What steps will reproduce the problem?**

1. Use the search/Replace text function (command-r)
2. Enter "." in the "Replace with" box
3. Click "Replace selection"

**What is the expected output? "."
What do you see instead?** `"\."`

**Please provide any additional information below**
The "Replace/find next" works fine

## Versions and main components

* Spyder Version: 3.2.0
Python 3.6.2 64bits, Qt 5.6.2, PyQt5 5.6 on Darwin


## Dependencies

Please go to the menu entry `Help > Optional Dependencies` (or
`Help > Dependencies`), press the button `Copy to clipboard`
and paste the contents below:
IPython >=4.0    :  6.1.0 (OK)
cython >=0.21    :  None (NOK)
jedi >=0.9.0     :  0.10.2 (OK)
nbconvert >=4.0  :  5.2.1 (OK)
numpy >=1.7      :  1.13.1 (OK)
pandas >=0.13.1  :  0.20.3 (OK)
psutil >=0.3     :  5.2.2 (OK)
pycodestyle >=2.3:  2.3.1 (OK)
pyflakes >=0.6.0 :  1.5.0 (OK)
pygments >=2.0   :  2.2.0 (OK)
pylint >=0.25    :  1.6.4 (OK)
qtconsole >=4.2.0:  4.3.0 (OK)
rope >=0.9.4     :  0.9.4-1 (OK)
sphinx >=0.6.6   :  1.6.2 (OK)
sympy >=0.7.3    :  None (NOK)



Discussion:
@andfoy, please take a look at this one.

Resolving patch:
diff --git a/spyder/widgets/findreplace.py b/spyder/widgets/findreplace.py
--- a/spyder/widgets/findreplace.py
+++ b/spyder/widgets/findreplace.py
@@ -29,6 +29,14 @@
 from spyder.widgets.comboboxes import PatternComboBox
 
 
+CONTROL_CHARACTERS = {
+    '\\n': '\n',
+    '\\r': '\r',
+    '\\t': '\t',
+    '\\f': '\f'
+}
+
+
 def is_position_sup(pos1, pos2):
     """Return True is pos1 > pos2"""
     return pos1 > pos2
@@ -515,6 +523,10 @@ def replace_find_selection(self, focus_replace_text=False):
                 replacement = re.sub(pattern, replace_text, seltxt, flags=re_flags)
             if replacement != seltxt:
                 cursor.removeSelectedText()
+                for plain_char in CONTROL_CHARACTERS:
+                    replacement = replacement.replace(
+                        plain_char, CONTROL_CHARACTERS[plain_char])
+                replacement = re.sub(r'\\(.)', r'\1', replacement)
                 cursor.insertText(replacement)
             cursor.endEditBlock()
             if focus_replace_text:


Test patch:
diff --git a/spyder/widgets/tests/test_editor.py b/spyder/widgets/tests/test_editor.py
--- a/spyder/widgets/tests/test_editor.py
+++ b/spyder/widgets/tests/test_editor.py
@@ -288,6 +288,21 @@ def test_replace_enter_press(editor_find_replace_bot):
     assert editor.get_cursor_line_column() == (3,4)
 
 
+def test_selection_replace_plain_regex(editor_find_replace_bot):
+    """Test that regex reserved characters are displayed as plain text."""
+    editor_stack, editor, finder, qtbot = editor_find_replace_bot
+    expected_new_text = ('.\\[()]*test bacon\n'
+                         'spam sausage\n'
+                         'spam egg')
+    old_text = editor.toPlainText()
+    finder.show()
+    finder.show_replace()
+    qtbot.keyClicks(finder.search_text, 'spam')
+    qtbot.keyClicks(finder.replace_text, '.\[()]*test')
+    qtbot.keyPress(finder.replace_text, Qt.Key_Return)
+    text = editor.toPlainText()[0:-1]
+    assert editor.toPlainText()[0:-1] == expected_new_text
+
 def test_advance_cell(editor_cells_bot):
     editor_stack, editor, qtbot = editor_cells_bot