Scala Programming Language
  1. Scala Programming Language
  2. SI-6631

Scala 2.10 String Interpolation inside a multiline String with backslash

    Details

      Description

      picked up from http://stackoverflow.com/questions/13296411/is-this-a-bug-in-scala-2-10-string-interpolation-inside-a-multiline-string-with.

      Here is the output from scala repl.
      Welcome to Scala version 2.10.0-RC1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6
      .0_33).
      Type in expressions to have them evaluated.
      Type :help for more information.

      scala> val fileName = "test"
      fileName: String = test

      scala> val path = s"""c:\foo\bar\$fileName.csv"""
      java.lang.StringIndexOutOfBoundsException: String index out of range: 11
      at java.lang.String.charAt(String.java:686)
      at scala.collection.immutable.StringOps$.apply$extension(StringOps.scala
      :39)
      at scala.StringContext$.treatEscapes(StringContext.scala:202)
      at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:90)
      at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:90)
      at scala.StringContext.standardInterpolator(StringContext.scala:120)
      at scala.StringContext.s(StringContext.scala:90)
      at .<init>(<console>:8)
      at .<clinit>(<console>)
      at .<init>(<console>:7)
      at .<clinit>(<console>)
      ...tuncated

      scala> val path = s"""c:\foo\bar$fileName.csv"""
      path: String = c:♀oo?artest.csv

      scala>

        Issue Links

          Activity

          Hide
          Rex Kerr added a comment -

          I know I should really have a pull request or at least a diff. But anyway, here's fixed code that

          (1) Throws the correct exception on an error

          (2) Does not fail on a short octal at the end of a string s"\4"

          (3) Uses the append(str, a, b) string builder method, which should be faster than substring (no object creation required)

            def treatEscapes(str: String): String = {
              lazy val bldr = new java.lang.StringBuilder
              val len = str.length
              var start = 0
              var cur = 0
              var idx = 0
              def output(ch: Char) = {
                bldr.append(str, start, cur)
                bldr append ch
                start = idx
              }
              while (idx < len) {
                cur = idx
                if (str(idx) == '\\') {
                  idx += 1
                  if (idx >= len) throw new InvalidEscapeException(str, cur)
                  if ('0' <= str(idx) && str(idx) <= '7') {
                    val leadch = str(idx)
                    var oct = leadch - '0'
                    idx += 1
                    if (idx < len && '0' <= str(idx) && str(idx) <= '7') {
                      oct = oct * 8 + str(idx) - '0'
                      idx += 1
                      if (idx < len && leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') {
                        oct = oct * 8 + str(idx) - '0'
                        idx += 1
                      }
                    }
                    output(oct.toChar)
                  } else {
                    val ch = str(idx)
                    idx += 1
                    output {
                      ch match {
                        case 'b' => '\b'
                        case 't' => '\t'
                        case 'n' => '\n'
                        case 'f' => '\f'
                        case 'r' => '\r'
                        case '\"' => '\"'
                        case '\'' => '\''
                        case '\\' => '\\'
                        case _ => throw new InvalidEscapeException(str, cur)
                      }
                    }
                  }
                } else {
                  idx += 1
                }
              }
              if (start == 0) str
              else bldr.append(str, start, idx).toString
            }
          

          It does not address the issue of it being weird that s"""\n""" gives you a carriage return. It also does not address the issue that s"\"" doesn't do what you think it will.

          Show
          Rex Kerr added a comment - I know I should really have a pull request or at least a diff. But anyway, here's fixed code that (1) Throws the correct exception on an error (2) Does not fail on a short octal at the end of a string s"\4" (3) Uses the append(str, a, b) string builder method, which should be faster than substring (no object creation required) def treatEscapes(str: String): String = { lazy val bldr = new java.lang.StringBuilder val len = str.length var start = 0 var cur = 0 var idx = 0 def output(ch: Char) = { bldr.append(str, start, cur) bldr append ch start = idx } while (idx < len) { cur = idx if (str(idx) == '\\') { idx += 1 if (idx >= len) throw new InvalidEscapeException(str, cur) if ('0' <= str(idx) && str(idx) <= '7') { val leadch = str(idx) var oct = leadch - '0' idx += 1 if (idx < len && '0' <= str(idx) && str(idx) <= '7') { oct = oct * 8 + str(idx) - '0' idx += 1 if (idx < len && leadch <= '3' && '0' <= str(idx) && str(idx) <= '7') { oct = oct * 8 + str(idx) - '0' idx += 1 } } output(oct.toChar) } else { val ch = str(idx) idx += 1 output { ch match { case 'b' => '\b' case 't' => '\t' case 'n' => '\n' case 'f' => '\f' case 'r' => '\r' case '\"' => '\"' case '\'' => '\'' case '\\' => '\\' case _ => throw new InvalidEscapeException(str, cur) } } } } else { idx += 1 } } if (start == 0) str else bldr.append(str, start, idx).toString } It does not address the issue of it being weird that s"""\n""" gives you a carriage return. It also does not address the issue that s"\"" doesn't do what you think it will.
          Hide
          Eran Medan added a comment - - edited

          Confirmed seeing this also in RC2

          Show
          Eran Medan added a comment - - edited Confirmed seeing this also in RC2
          Hide
          Jason Zaugg added a comment -

          Rex's suggestions:

          https://github.com/scala/scala/pull/1690

          To the original reporter: you should use raw"c:\foo\bar" or raw"""c:\foo\bar""" to avoid string escape processing. But beware, unicode escapes, e.g \u1234 are still processed as they happen much much earlier. So raw"c:\users" doesn't work. You can actually turn off unicode escape processing with the compiler option -Xno-uescape. Or make your life easier, and use '/' in strings as path separators.

          Show
          Jason Zaugg added a comment - Rex's suggestions: https://github.com/scala/scala/pull/1690 To the original reporter: you should use raw"c:\foo\bar" or raw"""c:\foo\bar""" to avoid string escape processing. But beware, unicode escapes, e.g \u1234 are still processed as they happen much much earlier. So raw"c:\users" doesn't work. You can actually turn off unicode escape processing with the compiler option -Xno-uescape . Or make your life easier, and use '/' in strings as path separators.
          Hide
          Jason Zaugg added a comment -

          I've submitted Rex's suggestions as https://github.com/scala/scala/pull/1690.

          Santosh: you can use raw"c:\foo\$filename" to avoid interpreting '\' as an escape character.

          But beware, \uNNNN is always treated as a unicode escape, unless you use the non-standard compiler option -Xno-uescape. I always use '/' as a path separator in literal strings to avoid these issues; even on Windows this is allowed.

          Show
          Jason Zaugg added a comment - I've submitted Rex's suggestions as https://github.com/scala/scala/pull/1690 . Santosh: you can use raw"c:\foo\$filename" to avoid interpreting '\' as an escape character. But beware, \uNNNN is always treated as a unicode escape, unless you use the non-standard compiler option -Xno-uescape . I always use '/' as a path separator in literal strings to avoid these issues; even on Windows this is allowed.
          Show
          Adriaan Moors added a comment - https://github.com/scala/scala/pull/1690

            People

            • Assignee:
              Jason Zaugg
              Reporter:
              Santosh Gokak
            • Votes:
              1 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development