Transform String concatenation into String.format with parameters - intellij-idea

Is the a way to make Intellij Idea to extract concatenated strings into String that uses String.format with parameteres, like:
transform:
String parameter = "the parameter";
String message = "the parameter of the message is: "+parameter;
into:
String parameter = "the parameter";
String message = String.format("the parameter of the message is: %s", parameter);

Now I found it. I thought it should be in the Refactor This/Extract menu:

Related

Kotlin string exists but can't use almost all string functionality

Summary: I have a string from which I can print and use substring, but can't use attributes such as length or functions such as .toInt() or .compareTo(), why would this be the case?
var s = "20"
val myToast = Toast.makeText(this, s, Toast.LENGTH_SHORT)
myToast.show()
//20
val myToast2 = Toast.makeText(this, s.length, Toast.LENGTH_SHORT)
myToast2.show()
//The app crashes with the error: android.content.res.Resources$NotFoundException: String resource ID #0x2
I can call substring on string s, but I can't call length, toInt(), compareTo(), etc.
The string clearly exists since I can print it and use substring but if that is true why does my app throw an error when I try to use other attributes and functions from it?
There are two overloads of Toast.makeText(). One accepts a String as the second argument, and displays that string. The other accepts an Int as the second argument, and displays whatever string resource has that integer id. (Normally you'd pass something like R.string.my_string here.)
When you call .length on your String, you'll get an Int back. And that means you wind up calling the second overload, which then looks for a string resource with the id 2. That doesn't exist, so you crash.
If you want to just display the number 2, then you need to make this a String again. You can use .toString() or "${s.length}", and so on.
Add .toString at the end of length,toInt(),compareTo(), etc. because s.length
return int :not String
Here is your modified answer
var s = "20"
val myToast = Toast.makeText(this, s, Toast.LENGTH_SHORT)
myToast.show()
//20
val myToast2 = Toast.makeText(this, s.length.toString(), Toast.LENGTH_SHORT)
myToast2.show()

String matching in scripts

I have a code to reply to all operator messages in SAP. I need it to be applied specifically based on string match. As i am new to scripts, I don't have much idea in which language it has been orignally written. Please help me with the issue. Thanks.
{
String query = "select OperatorMessage.* from OperatorMessage";
for (OperatorMessage oMessage : jcsSession.executeObjectQuery(OperatorMessage.TYPE, query))
{
//Check the operator message requires a reply
if (oMessage.getReplyStatus() == ReplyStatus.valueOf("Required"))
{
oMessage.setReply("Acknowledge");
jcsSession.persist();
}
}
}
My expected output should be, that it should work only with the provided string for string match. Example of such string can be:
"Please check PROCESS_X_215, 4693422521, in XYZ_Queue with status Error"

Kotlin String substitution not working when string is read from file

I have written a code that reads a text file. The text files contain placeholders which I would like to replace. The substitution does not work this way and the string is printed with the placeholders. Here is the code that I have written for this:
class TestSub(val sub: Sub) {
fun create() = template()
fun template() = Files.newBufferedReader(ClassPathResource(templateId.location).file.toPath()).readText()
}
data class Sub(val name: String, val age: Int)
Here is the main function that tries to print the final string:
fun main(args: Array<String>) {
val sub = Sub("Prashant", 32)
println(TestSub(sub).create())
}
However, when, instead of reading a file, I use a String, the following code works (Replacing fun template())
fun template() = "<h1>Hello ${sub.name}. Your age is ${sub.age}</h1>"
Is there a way to make string Substitution work when reading the content of a file?
Kotlin does not support String templates from files. I.e. code like "some variable: $variable" gets compiled to "some variable: " + variable. String templates are handled at compile time, which means it does not work with text loaded from files, or if you do something else to get the String escaped into a raw form. Either way, it would, as danielspaniol mentioned, be a security threat.
That leaves three options:
String.format(str)
MessageFormat.format(str)
Creating a custom engine
I don't know what your file contains, but if it's the String you used in the template function, change it to:
<h1>Hello {0}. Your age is {1,integer}</h1>
This is for MessageFormat, which is my personal preference. If you use String.format, use %s instead, and the other appropriate formats.
Now, use that in MessageFormat.format:
val result = MessageFormat.format(theString, name, age);
Note that if you use MessageFormat, you'll need to escape ' as ''. See this.
String substitution using ${...} is part of the string literals syntax and works roughly like this
val a = 1
val b = "abc ${a} def" // gets translated to something like val b = "abc " + a + " def"
So there is no way for this to work when you load from a text file. This would also be a huge security risk as it would allow for arbitrary code execution.
However I assume that Kotlin has something like a sprintf function where you can have placeholders like %s in your string and you can replace them with values
Take a look here. It looks like the easiest way is to use String.format
You are looking for something similar to Kotlin String templates for raw Strings, where placeholders like $var or ${var} are substituted by values, but this functionality needs to be available at runtime (for text read from files).
Methods like String.format(str) or MessageFormat.format(str) use other formats than the notation with the dollar prefix of Kotlin String templates. For "Kotlin-like" placeholder substitution you could use the function below (which I developed for similar reasons). It supports placeholders as $var or ${var} as well as dollar escaping by ${'$'}
/**
* Returns a String in which placeholders (e.g. $var or ${var}) are replaced by the specified values.
* This function can be used for resolving templates at RUNTIME (e.g. for templates read from files).
*
* Example:
* "\$var1\${var2}".resolve(mapOf("var1" to "VAL1", "var2" to "VAL2"))
* returns VAL1VAL2
*/
fun String.resolve(values: Map<String, String>): String {
val result = StringBuilder()
val matcherSimple = "\\$([a-zA-Z_][a-zA-Z_0-9]*)" // simple placeholder e.g. $var
val matcherWithBraces = "\\$\\{([a-zA-Z_][a-zA-Z_0-9]*)}" // placeholder within braces e.g. ${var}
// match a placeholder (like $var or ${var}) or ${'$'} (escaped dollar)
val allMatches = Regex("$matcherSimple|$matcherWithBraces|\\\$\\{'(\\\$)'}").findAll(this)
var position = 0
allMatches.forEach {
val range = it.range
val placeholder = this.substring(range)
val variableName = it.groups.filterNotNull()[1].value
val newText =
if ("\${'\$'}" == placeholder) "$"
else values[variableName] ?: throw IllegalArgumentException("Could not resolve placeholder $placeholder")
result.append(this.substring(position, range.start)).append(newText)
position = range.last + 1
}
result.append(this.substring(position))
return result.toString()
}
String templates only work for compile-time Sting literals, while what u read from a file is generated at runtime.
What u need is a template engine, which can render templates with variables or models at runtime.
For simple cases, String.format or MessageFormat.format in Java would work.
And for complex cases, check thymeleaf, velocity and so on.

String interpolation outputs enum name instead of value

I was hoping someone can explain this default functionality regarding string interpolation and the enum type.
I have this enum:
public enum CommentType
{
MyComment = 24,
TheirComment = 25,
AnotherComment = 26
}
I am using it in a string:
Dim sDateModified As String
sDateModified = $"<div name='commenttype{CommentType.MyComment}'></div>"
I was expecting CommentType.MyComment to be evaluated and the int value 24 to be used. The result should be: <div name='commenttype24'></div>
But what actually happens is that the identifier is used instead, giving me: <div name='commenttypeMyComment'></div>
In order to get the enum value I had to convert it to an integer:
sDateModified = $"<div name='commenttype{Convert.ToInt32(CommentType.MyComment)}'></div>"
It just feels counter intuitive to me. Can someone explain or point me to documentation on why it works this way?
You're getting the string value MyComment because that's what is returned by:
CommentType.MyComment.ToString()
Methods like String.Format and Console.WriteLine will automatically call ToString() on anything that isn't already a string. The string interpolation syntax $"" is just syntactic sugar for String.Format, which is why string interpolation also behaves this way.
Your workaround is correct. For slightly more compact code, you could do:
CInt(CommentType.MyComment)
You just need to use a format string in the interpolated value to force the result to integer format.
Dim sDateModified As String
sDateModified = $"<div name='commenttype{CommentType.MyComment:D}'></div>"

VB.NET String.Format FormatException was unhandled

I want to generate a json string but
What did I do is wrong? Why to this code throws an An unhandled exception
Public Function GenerateJsonString(doer As Integer, comment As String, id As Integer) As String
Dim jsonString As String = String.Format("{done_by:{0}, comment:{1}, request_id:{2}}", doer, comment, id)
Return jsonString
End Function
An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll
Additional information: Input string was not in a correct format.
The bracket { is a special character in string.format so you need to use two brackets if you want them in the output like so:
Dim jsonString As String = String.Format("{{done_by:{0}, comment:{1}, request_id:{2}}}", 806, "comment", 16233)
It outputs
{done_by:806, comment:comment, request_id:16233}
Which is not valid json since it's missing the "-characters. So to correct that you could do
Dim jsonString As String = String.Format("{{""done_by"":{0}, ""comment"":""{1}"", ""request_id"":{2}}}", 806, "comment", 16233)
Note that comment is string and also needs the "-characters in value.
Output is correct json:
{"done_by":806, "comment":"comment", "request_id":16233}
There is also easier and more robust way to do this by serialization:
Dim serializer As New System.Web.Script.Serialization.JavaScriptSerializer
Dim jsonString As String = serializer.Serialize(New With {.done_by = 806, .comment = "comment", .request_id = 16233})
If you have class library or windows -project it needs System.Web.Extensions reference to your project.
Good luck!
The issue is the fact that you have braces in your literal text. When calling String.Format, braces are used to indicate place-holders but you have an opening brace at the beginning of the text and a closing brace at the end. If you want those literal braces included then you must escape them, i.e.
"{{done_by:{0}, comment:{1}, request_id:{2}}}"