Parametric string replacement - java

I am running in to bit of a trouble trying to use parametric replacement.
In my properties file I have the following entry
tpi.message=This is a test message. Generated for ? on ? .
The text above is displayed on the web and in the report therefore I need to replace ? with parameters.
However, I can't use replace* method because ? is special character for regex. I also don't want to use String.format method.
I know it is possible to replace ? but I don't remember how.
Your help is appreciated.

You can do it like this:
String message = "This is a test message. Generated for ? on ?";
message = message.replaceFirst("\\?", "Bob").replaceFirst("\\?", "Tuesday");
System.out.println(message); // This is a test message. Generated for Bob on Tuesday

Related

How to check i18n message resource arguments is empty or not?

I mean for example this is my messages.properties file:
BFF.ERROR.PRODUCT_NOT_FOUND = Product with {0} not found
I want to do that if the arguments array is empty, the client shouldn't see the message like this
Product with {0} not found
I want to the user see this one
Product not found.
Can I do something like that?
BFF.ERROR.PRODUCT_NOT_FOUND = Product with {0} not found | Product not found
I think u can define two keys :
BFF.ERROR.PRODUCT_NOT_FOUND = Product with {0} not found
BFF.NULL.PRODUCT_NOT_FOUND = Product not found
then deal with it in code
Why would the arguments array be empty? Can you not use two different keys and check ahead of time to use the correct message based on the arguments? They're two different messages and should have their own keys.
messages.properties
key1=message with argument {0}
key2=message without argument
Somewhere in your code
final String msg;
if (condition) {
msg = ... // if you have the argument for placeholder {0}, get message for key1
} else {
msg = ... // fallback, get message for key2
}
If you really wanted to you could look into creating a custom message source and/or supporting beans and handle this kind of thing there but it seems like more trouble than it's worth. In that case, have a look at the MessageSourceSupport class Spring provides, in particular methods formatMessage and renderDefaultMessage.

Structured logging where logger argument not wanted in message

I'm using structured logging in a Spring Boot app using logstash and sometimes I want to include key values in the log that I don't want to be used in the message of the log. Is there a StructuredArgument or similar that allows for this?
An example of what I am doing currently is something like this:
// import lombok.extern.slf4j.Slf4j;
// import static net.logstash.logback.argument.StructuredArguments.kv;
// import static net.logstash.logback.argument.StructuredArguments.v;
log.info(
"My message with one arg {}",
v("key1":"arg I want to include value in place of placeholder in message and in json as key/value"),
kv("key2", "arg I only want in the json and not in the message"))
Everything works as I intended, by which I mean the log includes both key value pairs and the message only includes the first value in place of the placeholder. The issue is that I get a warning from the compiler which is flagged by intellij (PlaceholderCountMatchesArgumentCount) about the second structured argument and I would like to avoid this without resorting to suppressing/ignoring it
You can use Markers and pass it before your logging message - more details on github.
logger.info(append("key2", "only json"),
"My message with one arg {}",
v("key1":"arg in msg and json"));
I personally don't like this because markers have different purpose, so if structured argument works for you, just ignore warning in IDE.
Anyway, all this json/structured implementations are workarounds for SLF4J 1.*, which has not built for that. There was SLF4J 2.0.0-alpha1 release almost a yeah ago, but it is still in alpha and I haven't used it. But it's API should be ready for key-values that are crusial in nowadays distributed log management systems.
You can make the log message as a constant String, then the code quality checks will not warn this
You can make the structured argument print nothing into the formatted message:
(1) include the second placeholder {} inside the message
(2) use keyValue() instead of kv()
(3) provide the optional messageFormatPattern parameter (JavaDoc) equal to ""
Adjusting your example:
log.info(
"My message with one arg {}{}", //note (1)
v("key1":"arg I want to include value in place of placeholder in message and in json as key/value"),
keyValue("key2", "arg I only want in the json and not in the message", "")) //note (2) + (3)
This will effectively replace the second placeholder with an empty string.

Check if a string ends in is valid or not in java using regex

I have the following requirement where in I need to do few things only if the given string ends in "Y" or "Years" or "YEARS".
I tried doing it using regex like this.
String text=1.5Y;
if(Pattern.matches("Y$",text) || Pattern.matches("YEARS$",text) || Pattern.matches("Years",text))
{
//do
}
However this is getting failed.
Can someone point me where I have gone wrong or suggest me any other feasible method.
EDIT:
Thanks.That helps.
Finally I have used "(?i)^.*Y(ears)?$| (?i)^.*M(onths)?$".
But I want to make more changes to make it perfect.
Let's say I have many strings.
Ideally only strings like 1.5Y or 0.5-3.5Y or 2.5/2.5-4.5Y should pass if check.
It can be number of years(Ex:2.5y) or the period of years(2.5-3.5y) or the no of years/period of years(Ex.2.5/3.5-4.5Y) nothing more.
More Examples:
--------------
Y -should fail;
MY - should fail;
1.5CY - should fail;
1.5Y-2.5Y should fail;
1.5-2.5Y should pass;
1.5Y/2.5-3.5Y should fail;
1.5/2.5-3.5Y should pass;
You don't need a regex here:
if(text.endsWith("Y") || ...)
matches method attempts to match full input so use:
^.*Y$
for your first pattern.
btw you can use a single regex for all 3 cases:
if (text.matches( "(?i)^.*Y(ears)?$" ) ) {...}
(?i) does ignore case match.
.*(?:Y|YEARS|Years)$
You can directly use this .Match matches from beginning.So yours is failing.
You can simply use the regex pattern:
if (Pattern.matches(".*(Y|YEARS|Years)$",text)) {/*do something*/}
/((?!0)\d+|0)(.\d+)?(?:years|year|y)/gi
https://regex101.com/r/gJ6xD2/2
var text = "1.6y 1.5years 1year 1.5h";
text.match(/((?!0)\d+|0)(\.\d+)?(?:years|year|y)/gi);
Result["1.6y", "1.5years", "1year"]
(?=^(0\.\d+|[1-9](?:\d+)?(?:\.\d+)?)(?:(\s+)?[\/-](\s+)?(?:0\.\d+|[1-9](?:\d+)?(?:\.\d+)?))*(?:\s+)?(?:y(?:(ea)?rs|ears?)?|m(?:onths?)?)$).*
https://regex101.com/r/kL7rQ1/3
Only thing I wasn't sure "2.3 - 4 / 6.2 y" format is acceptable or not, so I've included it.

Regex submitting with empty string

I have the following REGEX that I'm serving up to java via an xml file.
[a-zA-Z -\(\) \-]+
This regex is used to validate server side and client side (via javascript) and works pretty well at allowing only alphabetic content and a few other characters...
My problem is that it will also allow zero lenth strings / empty through.
Does anyone have a simple and yet elegant solution to this?
I already tried...
[a-zA-Z -\(\) \-]{1,}+
but that didn;t seem to work.
Cheers!
UPDATE FOLLOWING INVESTIGATION
It appears the code I provided does in fact work...
String inputStr = " ";
String pattern = "[a-zA-Z -\\(\\) \\-]+";
boolean patternMatched = java.util.regex.Pattern.matches(pattern, inputStr);
if ( patternMatched ){
out.println("Pattern MATCHED");
}else{
out.println("NOT MATCHED");
}
After looking at this more closely I think the problem may well be within the logic of some of my java bean coding... It appears the regex is dropped out at the point where the string parse should take place, thereby allowing empty strings to be submitted... And also any other string... EEJIT that I am...
Cheers for the help in peer reviewing my initial stupid though....!
Have you tried this:
[a-zA-Z -\(\) \-]+

convert at symbol ("#") to CharSequence

I am testing site with selenium and I need to send an e-mail to one of the fields. So far I am using this Java method:
String email = "test#example.com"
WebElement emailField = driver.findElement(By.id("mainForm:accountPanelTabId:1:accountEmails");
emailField.sendKeys(email);
But from (to me) uknown reason, this is sending exactly this value to the field:
testvexample.com
(so basically the "#" got replaced by "v")
Just out of curiosity: I am Czech and have Czech keyboard. One shortcut to write "#" symbol is rightAlt + v so I believe this can be connected...
So I am searching any "bulletproof" methot which always writes "#" symbol. Any help appreciated.
EDIT
the sendKeys is method of Selenium, and it simulates typing on keyboard. The javadoc is here: http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/WebElement.html#sendKeys%28java.lang.CharSequence...%29
The following should work: String email = "test\u0040example.com";
Apologies for misreading the question earlier.
I think you will have to call sendKeys using the proper values from the Keys enum to simulate the way you get your at-sign. Use Keys.ALT with your "v" in a chord:
sendKeys(Keys.chord(Keys.ALT, "v"));

Categories