Repository: spyder-ide/spyder

Issue:
prefix 'b' of bytes is not highlighting in the editor window
## Description

**What steps will reproduce the problem?**

when inputting the bytes-type string in the editor window, the prefix 'b' is not highlighting with the same color of string.

**What is the expected output? What do you see instead?**


**Please provide any additional information below**



## Version and main components

* Spyder Version: 3.2.0 
* Python Version: 3.6.1
* Qt Versions: 5.6.2, PyQt5 5.6 on Windows

## Dependencies
```
pyflakes >=0.6.0 :  1.5.0 (OK)
pycodestyle >=2.3:  2.3.1 (OK)
pygments >=2.0   :  2.2.0 (OK)
pandas >=0.13.1  :  0.20.1 (OK)
numpy >=1.7      :  1.12.1 (OK)
sphinx >=0.6.6   :  1.6.3 (OK)
rope >=0.9.4     :  0.10.5 (OK)
jedi >=0.9.0     :  0.10.2 (OK)
nbconvert >=4.0  :  5.2.1 (OK)
sympy >=0.7.3    :  1.0 (OK)
cython >=0.21    :  0.25.2 (OK)
qtconsole >=4.2.0:  4.3.0 (OK)
IPython >=4.0    :  5.3.0 (OK)
pylint >=0.25    :  1.7.2 (OK)

```



Discussion:
@fanstvn could you add a screenshot?
I don't think we're going to address this, but pull requests are welcome.
@ccordoba12 I think it should be fairly simple? also we should add f strings, no?

https://github.com/spyder-ide/spyder/blob/master/spyder/utils/syntaxhighlighters.py#L345

Adding `f` and `b` in there?

Resolving patch:
diff --git a/spyder/utils/syntaxhighlighters.py b/spyder/utils/syntaxhighlighters.py
--- a/spyder/utils/syntaxhighlighters.py
+++ b/spyder/utils/syntaxhighlighters.py
@@ -26,7 +26,7 @@
 from spyder import dependencies
 from spyder.config.base import _
 from spyder.config.main import CONF
-from spyder.py3compat import builtins, is_text_string, to_text_string
+from spyder.py3compat import builtins, is_text_string, to_text_string, PY3
 from spyder.utils.sourcecode import CELL_LANGUAGES
 from spyder.utils.editor import TextBlockHelper as tbh
 from spyder.utils.workers import WorkerManager
@@ -340,14 +340,20 @@ def make_python_patterns(additional_keywords=[], additional_builtins=[]):
                   r"\b[+-]?0[oO][0-7]+[lL]?\b",
                   r"\b[+-]?0[bB][01]+[lL]?\b",
                   r"\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?[jJ]?\b"])
-    sqstring =     r"(\b[rRuU])?'[^'\\\n]*(\\.[^'\\\n]*)*'?"
-    dqstring =     r'(\b[rRuU])?"[^"\\\n]*(\\.[^"\\\n]*)*"?'
-    uf_sqstring =  r"(\b[rRuU])?'[^'\\\n]*(\\.[^'\\\n]*)*(\\)$(?!')$"
-    uf_dqstring =  r'(\b[rRuU])?"[^"\\\n]*(\\.[^"\\\n]*)*(\\)$(?!")$'
-    sq3string =    r"(\b[rRuU])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
-    dq3string =    r'(\b[rRuU])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
-    uf_sq3string = r"(\b[rRuU])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(\\)?(?!''')$"
-    uf_dq3string = r'(\b[rRuU])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(\\)?(?!""")$'
+    if PY3:
+        prefix = "r|u|R|U|f|F|fr|Fr|fR|FR|rf|rF|Rf|RF|b|B|br|Br|bR|BR|rb|rB|Rb|RB"
+    else:
+        prefix = "r|u|ur|R|U|UR|Ur|uR|b|B|br|Br|bR|BR"
+    sqstring =     r"(\b(%s))?'[^'\\\n]*(\\.[^'\\\n]*)*'?" % prefix
+    dqstring =     r'(\b(%s))?"[^"\\\n]*(\\.[^"\\\n]*)*"?' % prefix
+    uf_sqstring =  r"(\b(%s))?'[^'\\\n]*(\\.[^'\\\n]*)*(\\)$(?!')$" % prefix
+    uf_dqstring =  r'(\b(%s))?"[^"\\\n]*(\\.[^"\\\n]*)*(\\)$(?!")$' % prefix
+    sq3string =    r"(\b(%s))?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" % prefix
+    dq3string =    r'(\b(%s))?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?' % prefix
+    uf_sq3string = r"(\b(%s))?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(\\)?(?!''')$" \
+                   % prefix
+    uf_dq3string = r'(\b(%s))?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(\\)?(?!""")$' \
+                   % prefix
     string = any("string", [sq3string, dq3string, sqstring, dqstring])
     ufstring1 = any("uf_sqstring", [uf_sqstring])
     ufstring2 = any("uf_dqstring", [uf_dqstring])


Test patch:
diff --git a/spyder/utils/tests/test_syntaxhighlighters.py b/spyder/utils/tests/test_syntaxhighlighters.py
--- a/spyder/utils/tests/test_syntaxhighlighters.py
+++ b/spyder/utils/tests/test_syntaxhighlighters.py
@@ -10,6 +10,7 @@
 from qtpy.QtGui import QTextDocument
 
 from spyder.utils.syntaxhighlighters import HtmlSH, PythonSH, MarkdownSH
+from spyder.py3compat import PY3
 
 def compare_formats(actualFormats, expectedFormats, sh):
     assert len(actualFormats) == len(expectedFormats)
@@ -47,6 +48,31 @@ def test_HtmlSH_unclosed_commend():
     compare_formats(doc.firstBlock().layout().additionalFormats(), res, sh)
 
 
+def test_python_string_prefix():
+    if PY3:
+        prefixes = ("r", "u", "R", "U", "f", "F", "fr", "Fr", "fR", "FR",
+                    "rf", "rF", "Rf", "RF", "b", "B", "br", "Br", "bR", "BR",
+                    "rb", "rB", "Rb", "RB")
+    else:
+        prefixes = ("r", "u", "ur", "R", "U", "UR", "Ur", "uR", "b", "B",
+                    "br", "Br", "bR", "BR")
+    for prefix in prefixes:
+        txt = "[%s'test', %s'''test''']" % (prefix, prefix)
+
+        doc = QTextDocument(txt)
+        sh = PythonSH(doc, color_scheme='Spyder')
+        sh.rehighlightBlock(doc.firstBlock())
+
+        offset = len(prefix)
+        res = [(0, 1, 'normal'),                     # |[|
+               (1, 6 + offset, 'string'),            # |{prefix}'test'|
+               (7 + offset, 2, 'normal'),            # |, |
+               (9 + offset, 10 + offset, 'string'),  # |{prefix}'''test'''|
+               (19 + 2*offset, 1, 'normal')]         # | |
+
+        compare_formats(doc.firstBlock().layout().additionalFormats(), res, sh)
+
+
 def test_Markdown_basic():
     txt = "Some __random__ **text** with ~~different~~ [styles](link_url)"