android get key from hashMap with utf-8 unicode - java

this code used for check if word in string in hashMap key
String[] arrs = message.split("(?<! ) |(?<= {2})");
for(int j = 0 ; j < arrs.length; j++){
if(AppConfig.hashMap.containsKey(arrs[j])){
int s = AppConfig.hashMap.get(arrs[j]);
} else
text.append(" "+arrs[j]);
}
and the hashMap its
public static Map<String, Integer> hashMap = new HashMap<String, Integer>()
{{
put(":)", R.drawable.emoji_1f60a_64);
put(":D", R.drawable.emoji_1f601_64);
put(":'(", R.drawable.emoji_1f622_64);
put(":P", R.drawable.emoji_1f61c_64);
put(";)", R.drawable.emoji_1f609_64);
put(":O", R.drawable.emoji_1f632_64);
put("-_-", R.drawable.emoji_1f620_64);
put(":*", R.drawable.emoji_1f618_64);
put("<3", R.drawable.emoji_2764_64);
put("^_^", R.drawable.emoji_2764_64);
}};
now its can replace :) with drawable emogi but the problem when i use another smile symbole
when i loop on string and compare every word if found in hashMap
if(AppConfig.hashMap.containsKey(arrs[j])) //found smile replace with emogi
its check if there are :) or :D in string but problem when there are smiles symbols like those
"😌","😃","😄","😞","😢","😷","😓","😰"
so the hashMap will be
public static Map<String, Integer> hashMap = new HashMap<String, Integer>()
{{
put("😌", R.drawable.emoji_1f60a_64);
put("😃", R.drawable.emoji_1f601_64);
put("😄", R.drawable.emoji_1f622_64);
put("😞", R.drawable.emoji_1f61c_64);
put("😢", R.drawable.emoji_1f609_64);
put("😷", R.drawable.emoji_1f632_64);
put("😓", R.drawable.emoji_1f620_64);
put("😰", R.drawable.emoji_1f618_64);
}};
here i have this string
hi how are you ? 😌 😃 😄
now when check if there are key in hashMap equal 😌 or 😃 ...
by
if(AppConfig.hashMap.containsKey(arrs[j]))
its fail and say no key with this string

You could create a dynamic pattern from the values in the hashmap (and reuse it because it's expensive to create a pattern it for every execution).
Take a look at https://stackoverflow.com/a/1326962/6709113
For example:
package aa;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
public class Test {
public static String replaceMultipleStrings(String message) {
Map<String,String> tokens = new HashMap<String,String>();
tokens.put("Garfield", "--Garfield--");
tokens.put("😌", "--😌--");
tokens.put("😃", "--😃--");
tokens.put("😄", "--😄--");
// Create pattern of the format "(cat|beverage)"
String patternString = "(" + StringUtils.join(tokens.keySet(), "|") + ")";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(message);
StringBuffer sb = new StringBuffer();
while(matcher.find()) {
matcher.appendReplacement(sb, tokens.get(matcher.group(1)));
}
matcher.appendTail(sb);
String result = sb.toString();
System.out.println(result);
return result;
}
public static void main(String[] args)
{
replaceMultipleStrings("hi how are you, my friend Garfield 😌 😃 😄?");
}
}
The result is: "hi how are you, my friend --Garfield-- --😌-- --😃-- --😄--?"
If performance is required, the HashMap and Pattern creation should be done only once.

Related

Regex reset capture groups

I have tried alterations using '|' but seems to be impossible to first parse map if possible, if not, just parse the value as a whole, but keeping the capture group as no 1/2, tried with branch reset group but didn't manage that way either. Any suggestions are welcome.
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Scratch {
public static void main(String[] args) {
final Pattern outerKeyPattern = Pattern.compile("([A-Z]+)\\((.*)\\)", Pattern.MULTILINE);
final Pattern innerPattern = Pattern.compile("([A-Z]+)\\((.*?)\\)");
// There will always be a value in the outer,
// but sometimes it's an inner map, i.e only need to solve this case, no other exeptions
String input = """
VALUE(123)
OUTERVALUE(INNERVALUE(123)OTHERVALUE(456))
""";
Map<String, Map<String, String>> outer = new HashMap<>();
Matcher matcher = outerKeyPattern.matcher(input);
while (matcher.find()) {
String key = matcher.group(1);
String value = matcher.group(2);
Matcher valueMatcher = innerPattern.matcher(value);
Map<String, String> innerMap = new HashMap<>();
while (valueMatcher.find()) {
innerMap.put(valueMatcher.group(1), valueMatcher.group(2));
}
outer.put(key, innerMap);
}
System.out.println(outer);
}
}
yields output:
{VALUE={}, OUTERVALUE={INNERVALUE=123, OTHERVALUE=456}}
I need to parse value also as key for the inner map and it's value as null:
{VALUE={123=}, OUTERVALUE={INNERVALUE=123, OTHERVALUE=456}}
Since you seem to process your data line by line and the comment in your snippet indicates that your data is well formed, you could first extract the whole content of the outter braces and then check if the value contains any nested key-value pairs. With some modifications to your regex, something like below might be what you are looking for:
public static void main(final String[] args) {
Pattern outerPattern = Pattern.compile("([A-Z]+)\\((.*)\\)");
Pattern innerPattern = Pattern.compile("([A-Z]+)\\(([^()]*)\\)");
String input = """
VALUE(123)
OUTERVALUE(INNERVALUE(123)OTHERVALUE(456))
""";
Map<String, Map<String, String>> outer = new HashMap<>();
input.lines().forEach(line -> {
Matcher matcher = outerPattern.matcher(line);
matcher.find();
String key = matcher.group(1);
String value = matcher.group(2);
Map<String, String> innerMap = new HashMap<>();
if (!innerPattern.asPredicate().test(value)) { //check if value doesn't contain any nested key-value-pairs
innerMap.put(value, "");
} else {
Matcher valueMatcher = innerPattern.matcher(value);
while (valueMatcher.find()) {
innerMap.put(valueMatcher.group(1), valueMatcher.group(2));
}
}
outer.put(key, innerMap);
});
System.out.println(outer);
}

How to replace tokens in java using regex?

I am having a string template containing $variables which needs to be replaced.
String Template: "hi my name is $name.\nI am $age old. I am $sex"
The solution which i tried verifying does not work in the java program.
http://regexr.com/3dtq1
Further, I referred to https://www.regex101.com/ where i could not check if the pattern works for java. But, while going through one of the tutorials I found that "$ Matches end of line". what's the best way to replace the tokens in the template with the variables?
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternCompiler {
static String text = "hi my name is $name.\nI am $age old. I am $sex";
static Map<String,String> replacements = new HashMap<String,String>();
static Pattern pattern = Pattern.compile("\\$\\w+");
static Matcher matcher = pattern.matcher(text);
public static void main(String[] args) {
replacements.put("name", "kumar");
replacements.put("age", "26");
replacements.put("sex", "male");
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
String replacement = replacements.get(matcher.group(1));
if (replacement != null) {
// matcher.appendReplacement(buffer, replacement);
// see comment
matcher.appendReplacement(buffer, "");
buffer.append(replacement);
}
}
matcher.appendTail(buffer);
System.out.println(buffer.toString());
}
}
You are using matcher.group(1) but you didn't define any group in the regexp (( )), so you can use only group() for the whole matched string, which is what you want.
Replace line:
String replacement = replacements.get(matcher.group(1));
With:
String replacement = replacements.get(matcher.group().substring(1));
Notice the substring, your map contains only words, but matcher will match also $, so you need to search in map for "$age".substring(1)" but do replacement on the whole $age.
You can try replacing the pattern string with
\\$(\\w+)
and the variable replacement works. Your current pattern only has group 0 (the entire pattern) but not group 1. Adding the parenthesis makes the first group the variable name and the replacement will replace the dollar sign and the variable name.
Your code has just minor glitches.
static Map<String,String> replacements = new HashMap<>();
static Pattern pattern = Pattern.compile("\\$\\w+\\b"); // \b not really needed
// As no braces (...) there is no group(1)
String replacement = replacements.get(matcher.group());
Your not using the right thing as your key. Change to group(), and change map to '$name' etc:
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HelloWorld {
static String text = "hi my name is $name.\nI am $age old. I am $sex";
static Map<String,String> replacements = new HashMap<String,String>();
static Pattern pattern = Pattern.compile("\\$\\w+");
static Matcher matcher = pattern.matcher(text);
public static void main(String[] args) {
replacements.put("$name", "kumar");
replacements.put("$age", "26");
replacements.put("$sex", "male");
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
String replacement = replacements.get(matcher.group());
System.out.println(replacement);
if (replacement != null) {
// matcher.appendReplacement(buffer, replacement);
// see comment
matcher.appendReplacement(buffer, "");
buffer.append(replacement);
}
}
matcher.appendTail(buffer);
System.out.println(buffer.toString());
}
}

Java: Replace RegEx with method outcome

I have the following scenario in my current Java project:
A properties file:
animal1=cat
animal2=dog
A Java method:
public String replace(String input) {
return input.replaceAll("%(.*?)%", properties.getProperty("$1"));
}
The part that says properties.getProperty("$1") obviously doesn't work because it will return the property for the key "$1" but not for the actual value for $1.
Is there any simple method to replace for example "%animal1%" with "cat"?
The properties file will contain a few hundred entries, so searching after a substring that could be replaced for every value in the properties file is not an option.
Don't try to do it as oneliner. If you use a loop to check for all the patterns that might match
Here's some code that will do the trick for you (this should compile and run as-is)
package org.test.stackoverflow;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternReplacer {
private final Pattern keyPattern = Pattern.compile("%([^%]*)%");
private final Properties properties;
public PatternReplacer(Properties propertySeed) {
properties = propertySeed;
}
public String replace(String input) {
int start = 0;
while(true) {
Matcher match = keyPattern.matcher(input);
if(!match.find(start)) break;
String group = match.group(1);
if(properties.containsKey(group)) {
input = input.replaceAll("%" + group + "%", properties.getProperty(group));
} else {
start = match.start() + group.length();
}
}
return input;
}
public static void main(String... args) {
Properties p = new Properties();
p.put("animal1", "cat");
p.put("animal2", "dog");
PatternReplacer test = new PatternReplacer(p);
String result = test.replace("foo %animal1% %bar% %animal2%baz %animal1% qu%ux");
System.out.println(result);
}
}
Output:
foo cat %bar% dogbaz cat qu%ux
If I understand you correctly you will need to use manually use appendReplacement and appendTail methods from Matcher class. This will allow you to pass result of properties.getProperty(matcher.group(1))
Here is basic example of how you can use it. In this example I'm searching for some keyword like string or secret to replace them. Replacement is decided dynamically based on mapping like
string->foo,
secret->whatever
and is determined by simply calling get(keyword) from Map which stores this mapping.
String data = "some string with some secret data";
Map<String,String> properties = new HashMap<>();
properties.put("string", "foo");
properties.put("secret", "whatever");
Pattern p = Pattern.compile("string|secret");
Matcher m = p.matcher(data);
StringBuffer sb = new StringBuffer();
while (m.find()){
m.appendReplacement(sb, properties.get(m.group()));//replace found match
//with result based on group
}
m.appendTail(sb);//append rest of text after last match, in our case " data"
String result = sb.toString();
System.out.println("Original: " + data);
System.out.println("Replaced: " + result);
Result:
Original: some string with some secret data
Replaced: some foo with some whatever data

Find the String Starts with $ symbol using Regular Expression

String str = "hai ${name} .... Welcome to ${sitename}....";
from this str i need to replace ${name} by "jack" and ${sitename} by "google"
is it possible to do with regular Expression ?
or
is there any other fastest way to replace the string .
EDITED :
name and sitename is the str variable is dynamic .
1.So first i have to find the key .
Eg : here name , sitename is the key
2.Then i have an Hashmap which has key value pairs .
based on the key value i have to replace the string in str variable.
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Replacer
{
public static String replacePlaceHolders(String text)
{
Map<String, String> fields = new HashMap<>();
fields.put("name", "jack");
fields.put("sitename", "google");
Pattern p = Pattern.compile("\\$\\{(.*?)\\}");
Matcher matcher = p.matcher(text);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String key = matcher.group(1);
if (!fields.containsKey(key)) {
continue;
}
matcher.appendReplacement(result, fields.get(key));
}
matcher.appendTail(result);
return result.toString();
}
public static void main(String[] args)
{
System.out.println(
replacePlaceHolders("hai ${name} .... Welcome to ${sitename}...."));
}
}
NO Regex is needed!
You could iterate the keySet of your map, and do:
str=str.replace("${"+key+"}", map.get(key));
about the method:
http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#replace(java.lang.CharSequence, java.lang.CharSequence)
I think you'd be better off using String.format
String str = String.format("hai %s .... Welcome to %s....", name, site);
Maybe this will help you:
\$\{name+\}
change ${name} to test
-> ${name} trete ${sitename} -> test trete ${sitename}
You have to escape this expression for usage in Java:
\\$\\{name+\\}
If you can replace ${name} and ${sitename} with {0} and {1} you could use MessageFormat.
String str = "hai {0} .... Welcome to {1}....";
String output = MessageFormat.format(str, new String[]{"jack","google"});

How to format message with argument names instead of numbers?

I have something like:
String text = "The user {0} has email address {1}."
// params = { "Robert", "myemailaddr#gmail.com" }
String msg = MessageFormat.format(text, params);
This isn't great for me, because sometimes my translators are not sure what goes in the {0} and {1}, also it would be nice to be able to reword the messages without worrying about the order of the args.
I'd like to replace the arguments with readable names instead of numbers. Something like this:
String text = "The user {USERNAME} has email address {EMAILADDRESS}."
// Map map = new HashMap( ... [USERNAME="Robert", EMAILADDRESS="myemailaddr#gmail.com"]
String msg = MessageFormat.format(text, map);
Is there an easy way to do this?
Thanks!
rob
You can use MapFormat for this. Find out the details here:
http://www.java2s.com/Code/Java/I18N/AtextformatsimilartoMessageFormatbutusingstringratherthannumerickeys.htm
String text = "The user {name} has email address {email}.";
Map map = new HashMap();
map.put("name", "Robert");
map.put("email", "rhume55#gmail.com");
System.out.println("1st : " + MapFormat.format(text, map));
OUTPUT:
1st : The user Robert has email address rhume55#gmail.com.
See StrSubstitutor from org.apache.commons.lang3:
Map valuesMap = HashMap();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StrSubstitutor sub = new StrSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);
// resolvedString: "The quick brown fox jumped over the lazy dog."
Easy to make one yourself. This is what I use (the main() function is just for test code):
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringTemplate {
final private String template;
final private Matcher m;
static final private Pattern keyPattern =
Pattern.compile("\\$\\{([a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)*)\\}");
private boolean blanknull=false;
public StringTemplate(String template) {
this.template=template;
this.m = keyPattern.matcher(template);
}
/**
* #param map substitution map
* #return substituted string
*/
public String substitute(Map<String, ? extends Object> map)
{
this.m.reset();
StringBuffer sb = new StringBuffer();
while (this.m.find())
{
String k0 = this.m.group();
String k = this.m.group(1);
Object vobj = map.get(k);
String v = (vobj == null)
? (this.blanknull ? "" : k0)
: vobj.toString();
this.m.appendReplacement(sb, Matcher.quoteReplacement(v));
}
this.m.appendTail(sb);
return sb.toString();
}
public StringTemplate setBlankNull()
{
this.blanknull=true;
return this;
}
static public void main(String[] args)
{
StringTemplate t1 = new StringTemplate("${this} is a ${test} of the ${foo} bar=${bar} ${emergency.broadcasting.system}");
t1.setBlankNull();
Map<String, String> m = new HashMap<String, String>();
m.put("this", "*This*");
m.put("test", "*TEST*");
m.put("foo", "$$$aaa\\\\111");
m.put("emergency.broadcasting.system", "EBS");
System.out.println(t1.substitute(m));
}
}
Your question is closely related to: How to replace a set of tokens in a Java String
You could use velocity or another template library. But there will be some pain because Java does not have any kind of Map literals.
I know my answer comes a little late, but if you still need this functionality, without the need to download a full-fledged template engine you can take a look at aleph-formatter (I am one of the authors):
Student student = new Student("Andrei", 30, "Male");
String studStr = template("#{id}\tName: #{st.getName}, Age: #{st.getAge}, Gender: #{st.getGender}")
.arg("id", 10)
.arg("st", student)
.format();
System.out.println(studStr);
Or you can chain the arguments:
String result = template("#{x} + #{y} = #{z}")
.args("x", 5, "y", 10, "z", 15)
.format();
System.out.println(result);
// Output: "5 + 10 = 15"
Internally it works using a StringBuilder creating the result by "parsing" the expression, no string concatenation, regex/replace is performed.
static final Pattern REPLACE_PATTERN = Pattern.compile("\\x24\\x7B([a-zA-Z][\\w\\x2E].*?)\\x7D");
/**
* Check for unresolved environment
*
* #param str
* #return origin if all substitutions resolved
*/
public static String checkReplacement(String str) {
Matcher matcher = REPLACE_PATTERN.matcher(str);
if (matcher.find()) {
throw LOG.getIllegalArgumentException("Environment variable '" + matcher.group(1) + "' is not defined");
}
return str;
}
// replace in str ${key} to value
public static String resolveReplacement(String str, Map<String, String> replacements) {
Matcher matcher = REPLACE_PATTERN.matcher(str);
while (matcher.find()) {
String value = replacements.get(matcher.group(1));
if (value != null) {
str = matcher.replaceFirst(replaceWindowsSlash(value));
}
}
return str;
}
But you loose all format options (like ##.#)

Categories

Resources