scala, string variable processed as string not regexp - string

Is it seamlessly possible to do?
scala> val p = "$"
scala> "hello, I have 65 dollars".replaceFirst("dollars", p)
Current result is
java.lang.StringIndexOutOfBoundsException: String index out of range: 1
....
The expected result in scala 2.10:
hello, I have 65 $
Problem is with variable p which stores symbol $, I need to process it as a string not regexp.
Note: I can't modify (e.g. replace all non-letter symbols) the p variable (only standard functions, e.g. .toString)
Note2: The given example is rather toy-example. I'd appreciate a more general solution. I.e. variable p can contain any type of content (symbols, numbers, text,...), therefore replacing "$" for "\\$" doesn.t make much sense
(this is improved version of similar problem: scala string, raw string )

Use Regex.quote for patterns and quoteReplacement for replacement strings. (These just call into Pattern.)
scala> import util.matching._
import util.matching._
scala> "hello, I have 65 dollars".replaceFirst("dollars", Regex quoteReplacement p)
res7: String = hello, I have 65 $
scala> "dollars".r replaceFirstIn ("hello, I have 65 dollars", Regex quoteReplacement p)
res8: String = hello, I have 65 $
scala> "hello, I have 65 dollars".replaceAllLiterally("dollars", p) // quotes both
res9: String = hello, I have 65 $

You need to escape the dollar sign literal, because Java uses it in its implementation of regular expressions as a group reference.
You noted that you can't modify the string literal in the p variable, so you need to resort to replacing the dollar sign and other special characters like this:
Pattern.quote(p);

The problem is replaceFirst() uses regular expressions so:
"65 dollars".replaceFirst("dollars","$0") // compiles
"65 dollars".replaceFirst("dollars","$") // throws "StringIndexOutOfBoundsException"
If,
val dollars = "$"
You could escape the $ symbol,
"65 dollars".replaceFirst( "dollars", if(dollars == "$") "\\$" else dollars )
or use string interpolation,
s"65 $dollars"
or go old school string manipulation,
val t = "65 dollars".split("dollars"); if(t.size>1) t.mkString(dollars) else t(0) + dollars
or with a map,
val ff = "dollars"
val r1 = "$"
"65 dollars, 3 dollars, 50 dollars".split(ff).zipWithIndex.map{case (t,0) => t+r1; case (t,_) => t+ff}.mkString

Related

How to transform "Umlaute" (ü) to "ue" in the string?

I have a string which is looking like this for example Lübeck Nürnberg Österreich with "Umlaute".
Now I want to split it and add the new "words" on the string like this Lübeck Nürnberg Österreich Luebeck Nuernberg Oesterreich.
So ä should be ae, ö should be oe and ü should be ue.
But I have no clue how to achieve this, thank you!
DATA: lt_split TYPE TABLE OF char40.
SPLIT string AT space INTO TABLE lt_split.
You can use REPLACE to replace a string with another string inside a string:
REPLACE ALL OCCURENCES OF: 'ä'
IN string
WITH 'ae',
'ü'
IN string
WITH 'ue'.
There is another variation of this statement, it can be used with an internal table:
REPLACE 'ä'
IN TABLE lt_split
WITH 'ae'.
https://help.sap.com/doc/abapdocu_751_index_htm/7.51/de-DE/abapreplace_in_pattern.htm
Please note, the new string will be longer (if at least one replacement happened), this can be a problem, if the string was character type with fixed length and the new string would be longer, than allowed.
You can use the function module SCP_REPLACE_STRANGE_CHARS, but you have less control than replace on what is changed.
Example:
DATA name TYPE string.
name = 'Lübeck Österreich Haßberge Eichstätt'.
CALL FUNCTION 'SCP_REPLACE_STRANGE_CHARS'
EXPORTING
intext = name
IMPORTING
outtext = name
EXCEPTIONS
invalid_codepage = 1
codepage_mismatch = 2
internal_error = 3
cannot_convert = 4
fields_not_type_c = 5
OTHERS = 6.
ASSERT name = 'Luebeck Oesterreich Hassberge Eichstaett'.
Be careful, the function module affects lots of characters with accent and lots of special characters, for instance, depending on the values of parameters, we may have these replacements:
á ==> AE
ā ==> A (Acircumflex)
Ă ==> Ae (Adieresis)
£ ==> L (sterling)
ß ==> ss (eszett)
¼ ==> 1/4
You may use the program RSCP0007 to test the function module.

Could anyone explain this spark expression for me?

I'm a new learner of spark. There's one line of code estimating pi but I don't quite understand how it works.
scala>val pi_approx = f"pi = ${355f/113}%.5f"
pi_approx: String = pi = 3.14159
I don't understand the 'f' '$' and '%' in the expression above. Could anyone explain the usage of them? Thanks!
This is the example of String Interpolation that allows users to embed variable references directly in processed string literals. For e.g.
scala> val name = "Scala"
name: String = Scala
scala> println(s"Hello, $name")
Hello, Scala
In above example the literal s"Hello, $name" is a processed string literal.
Scala provides three string interpolation methods out of the box: s, f and raw.
Prepending f to any string literal allows the creation of simple formatted strings, similar to printf in other languages.
The formats allowed after the % character tells that result is formatted as a decimal number while ${} allows any arbitrary expression to be embedded. For e.g.
scala> println(s"1 + 1 = ${1 + 1}")
1 + 1 = 2
More detailed information can be found on:
Scala String Interpolation
Java Formatter

What's the difference between raw string interpolation and triple quotes in scala

Scala has triple quoted strings """String\nString""" to use special characters in the string without escaping. Scala 2.10 also added raw"String\nString" for the same purpose.
Is there any difference in how raw"" and """""" work? Can they produce different output for the same string?
Looking at the source for the default interpolators (found here: https://github.com/scala/scala/blob/2.11.x/src/library/scala/StringContext.scala) it looks like the "raw" interpolator calls the identity function on each letter, so what you put in is what you get out. The biggest difference that you will find is that if you are providing a string literal in your source that includes the quote character, the raw interpolator still won't work. i.e. you can't say
raw"this whole "thing" should be one string object"
but you can say
"""this whole "thing" should be one string object"""
So you might be wondering "Why would I ever bother using the raw interpolator then?" and the answer is that the raw interpolator still performs variable substitution. So
val helloVar = "hello"
val helloWorldString = raw"""$helloVar, "World"!\n"""
Will give you the string "hello, "World"!\n" with the \n not being converted to a newline, and the quotes around the word world.
It is surprising that using the s-interpolator turns escapes back on, even when using triple quotes:
scala> "hi\nthere."
res5: String =
hi
there.
scala> """hi\nthere."""
res6: String = hi\nthere.
scala> s"""hi\nthere."""
res7: String =
hi
there.
The s-interpolator doesn't know that it's processing string parts that were originally triple-quoted. Hence:
scala> raw"""hi\nthere."""
res8: String = hi\nthere.
This matters when you're using backslashes in other ways, such as regexes:
scala> val n = """\d"""
n: String = \d
scala> s"$n".r
res9: scala.util.matching.Regex = \d
scala> s"\d".r
scala.StringContext$InvalidEscapeException: invalid escape character at index 0 in "\d"
at scala.StringContext$.loop$1(StringContext.scala:231)
at scala.StringContext$.replace$1(StringContext.scala:241)
at scala.StringContext$.treatEscapes0(StringContext.scala:245)
at scala.StringContext$.treatEscapes(StringContext.scala:190)
at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
at scala.StringContext.standardInterpolator(StringContext.scala:124)
at scala.StringContext.s(StringContext.scala:94)
... 33 elided
scala> s"""\d""".r
scala.StringContext$InvalidEscapeException: invalid escape character at index 0 in "\d"
at scala.StringContext$.loop$1(StringContext.scala:231)
at scala.StringContext$.replace$1(StringContext.scala:241)
at scala.StringContext$.treatEscapes0(StringContext.scala:245)
at scala.StringContext$.treatEscapes(StringContext.scala:190)
at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
at scala.StringContext$$anonfun$s$1.apply(StringContext.scala:94)
at scala.StringContext.standardInterpolator(StringContext.scala:124)
at scala.StringContext.s(StringContext.scala:94)
... 33 elided
scala> raw"""\d$n""".r
res12: scala.util.matching.Regex = \d\d

How to insert double quotes into String with interpolation in scala

Having trouble escaping all the quotes in my function
(basic usage of it -> if i find a string do nothing, if its not a string add " in the begin and end)
code snippet :
def putTheDoubleQuotes(value: Any): Any = {
value match {
case s: String => s //do something ...
case _ => s"\"$value\"" //not working
}
}
only thing that worked was :
case _ => s"""\"$value\""""
is there a better syntax for this ?
it looks terrible and the IDE (IntelliJ) marks it in red (but lets you run it which really pisses me!!!!!)
This is a bug in Scala:
escape does not work with string interpolation
but maybe you can use:
scala> import org.apache.commons.lang.StringEscapeUtils.escapeJava
import org.apache.commons.lang.StringEscapeUtils.escapeJava
scala> escapeJava("this is a string\nover two lines")
res1: java.lang.String = this is a string\nover two lines
You don't need to escape quotes in triple-quoted string, so s""""$value""""" will work. Admittedly, it doesn't look good either.
Another solution (also mentioned in the Scala tracker) is to use
case _ => s"${'"'}$value${'"'}"
Still ugly, but sometimes perhaps may be preferred over triple quotes.
It seems an escape sequence $" was suggested as a part of SIP-24 for 2.12:
case _ => s"$"$value$""
This SIP was never accepted, as it contained other more controversial suggestions. Currently there is an effort to get escape sequence $" implemented in 2.13 as Pre SIP/mini SIP $” escapes in interpolations.
An example:
scala> val username="admin"
> username: String = admin
scala> val pass="xyz"
> pass: String = xyz
scala> println(s"""{"username":"$username", "pass":"$pass"}""")
> {"username":"admin", "pass":"xyz"}
This fixed the problem for me, I tested this out and this is what I used.
raw"""
Inside this block you can put "as many" quotes as you "want" and even "${5 + 7}" interpolate inside the quotes
"""
http://docs.scala-lang.org/overviews/core/string-interpolation.html#the-raw-interpolator
For your use case, they make it easy to achieve nice syntax.
scala> implicit class `string quoter`(val sc: StringContext) {
| def q(args: Any*): String = "\"" + sc.s(args: _*) + "\""
| }
defined class string$u0020quoter
scala> q"hello,${" "*8}world"
res0: String = "hello, world"
scala> "hello, world"
res1: String = hello, world // REPL doesn't add the quotes, sanity check
scala> " hello, world "
res2: String = " hello, world " // unless the string is untrimmed
Squirrel the implicit away in a package object somewhere.
You can name the interpolator something besides q, of course.
Last week, someone asked on the ML for the ability to use backquoted identifiers. Right now you can do res3 but not res4:
scala> val `"` = "\""
": String = "
scala> s"${`"`}"
res3: String = "
scala> s"hello, so-called $`"`world$`"`"
res4: String = hello, so-called "world"
Another idea that just occurred to me was that the f-interpolator already does some work to massage your string. For instance, it has to handle "%n" intelligently. It could, at the same time, handle an additional escape "%q" which it would not pass through to the underlying formatter.
That would look like:
scala> f"%qhello, world%q"
<console>:9: error: conversions must follow a splice; use %% for literal %, %n for newline
That's worth an enhancement request.
Update: just noticed that octals aren't deprecated in interpolations yet:
scala> s"\42hello, world\42"
res12: String = "hello, world"
As already mentioned, this is a known bug in Scala. A workaround is to use \042.
Simple way:-
val str="abc"
println(s"$str") //without double quotes
println(s"""\"$str\"""") // with double quotes
Starting Scala 2.13.6 escaped double quotes work as expected in string interpolations
Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java 15.0.2).
Type in expressions for evaluation. Or try :help.
scala> s"\"Hello\""
val res0: String = "Hello"
scala> s"$"Hello$""
val res1: String = "Hello"
How about
s"This is ${"\"" + variable + "\""}" inserted in string with quotes
It's heavily used in my case, therefore I created this version:
object StringUtil{
implicit class StringImprovements(s: String) {
def quoted = "\""+s+"\""
}
}
val myStatement = s"INSERT INTO ${tableName.quoted} ..."
Taking #Pascalius suggestion a few steps further. class StringImprovements extends and inherits AnyVal.
object StringUtil{
implicit class StringImprovements(val s: String) extends AnyVal {
def dqt = "\""+s+"\"" // double quote
def sqt = s"'$s'" // single quote
}
}
Scala only uses the StringImprovements class to create an intermediate object on which to call implicitly the two extension methods dqt & sqt. Nevertheless, we can eliminate the creation of this object and improve performance by making the class inherit from AnyVal. For Scala provides the value type specifically for such cases where the compiler will replace the object by just making the call to the method directly.
Here is a simple example using the above implicit class in an intermix where we use named variables (string & boolean) and a function in the interpolation string.
import StringUtil._
abstract class Animal {
...
override def toString(): String = s"Animal:${getFullName().dqt}, CanFly:$canFly, Sound:${getSound.dqt}"
}
The following worked for me inside my terminal.
scala> val str: String = hi
scala> print(str)
hi~
scala> print(s"${str}")
hi~
scala> print(s"\"${str}\"")
"hi"~
scala> print(s"\"$str\"")
"hi"~
scala>

Scala: How can I get an escaped representation of a string?

Basically, what I'd like to do is have:
// in foo.scala
val string = "this is a string\nover two lines"
println(string)
println(foo(string))
Do this:
% scala foo.scala
this is a string
over two lines
"this is a string\nover two lines"
Basically looking for an analog of ruby's String#inspect or haskell's show :: String -> String.
This question is a bit old but I stumbled over it while searching for a solution myself and was dissatisfied with the other answers because they either are not safe (replacing stuff yourself) or require an external library.
I found a way to get the escaped representation of a string with the scala standard library (>2.10.0) which is safe. It uses a little trick:
Through runtime reflection you can can easily obtain a representation of a literal string expression. The tree of such an expression is returned as (almost) scala code when calling it's toString method. This especially means that the literal is represented the way it would be in code, i.e. escaped and double quoted.
def escape(raw: String): String = {
import scala.reflect.runtime.universe._
Literal(Constant(raw)).toString
}
The escape function therefore results in the desired code-representation of the provided raw string (including the surrounding double quotes):
scala> "\bHallo" + '\n' + "\tWelt"
res1: String =
?Hallo
Welt
scala> escape("\bHallo" + '\n' + "\tWelt")
res2: String = "\bHallo\n\tWelt"
This solution is admittedly abusing the reflection api but IMHO still safer and more maintainable than the other proposed solutions.
I'm pretty sure this isn't available in the standard libraries for either Scala or Java, but it is in Apache Commons Lang:
scala> import org.apache.commons.lang.StringEscapeUtils.escapeJava
import org.apache.commons.lang.StringEscapeUtils.escapeJava
scala> escapeJava("this is a string\nover two lines")
res1: java.lang.String = this is a string\nover two lines
You could easily add the quotation marks to the escaped string if you wanted, of course.
The scala.reflect solution actually works fine. When you do not want to pull in that whole library, this is what it seems to do under the hood (Scala 2.11):
def quote (s: String): String = "\"" + escape(s) + "\""
def escape(s: String): String = s.flatMap(escapedChar)
def escapedChar(ch: Char): String = ch match {
case '\b' => "\\b"
case '\t' => "\\t"
case '\n' => "\\n"
case '\f' => "\\f"
case '\r' => "\\r"
case '"' => "\\\""
case '\'' => "\\\'"
case '\\' => "\\\\"
case _ => if (ch.isControl) "\\0" + Integer.toOctalString(ch.toInt)
else String.valueOf(ch)
}
val string = "\"this\" is a string\nover two lines"
println(quote(string)) // ok
If I compile these:
object s1 {
val s1 = "this is a string\nover two lines"
}
object s2 {
val s2 = """this is a string
over two lines"""
}
I don't find a difference in the String, so I guess: There is no possibility, to find out, whether there was was a "\n" in the source.
But maybe I got you wrong, and you would like to get the same result for both?
"\"" + s.replaceAll ("\\n", "\\\\n").replaceAll ("\\t", "\\\\t") + "\""
The second possibility is:
val mask = Array.fill (3)('"').mkString
mask + s + mask
res5: java.lang.String =
"""a
b"""
Test:
scala> val s = "a\n\tb"
s: java.lang.String =
a
b
scala> "\"" + s.replaceAll ("\\n", "\\\\n").replaceAll ("\\t", "\\\\t") + "\""
res7: java.lang.String = "a\n\tb"
scala> mask + s + mask
res8: java.lang.String =
"""a
b"""
You could build your own function pretty easily, if you don't want to use the apache library:
scala> var str = "this is a string\b with some \n escapes \t so we can \r \f \' \" see how they work \\";
str: java.lang.String =
this is a string? with some
escapes so we can
' " see how they work \
scala> print(str.replace("\\","\\\\").replace("\n","\\n").replace("\b","\\b").replace("\r","\\r").replace("\t","\\t").replace("\'","\\'").replace("\f","\\f").replace("\"","\\\""));
this is a string\b with some \n escapes \t so we can \r \f \' \" see how they work \\
Maybe there is a cleaner way to implement this in Scala 3, but this is what I've come up with following #martin-ring approach:
import scala.quoted.*
inline def escape(inline raw: String): String = ${escapeImpl('{raw})}
def escapeImpl(raw: Expr[String])(using Quotes): Expr[String] =
import quotes.reflect.*
Literal(StringConstant(raw.show)).asExprOf[String]

Resources