String _p = p;
for(int i = 0; i <= _p.length()-1; i++)
_p = _p.replace(lChar[_p.charAt(i)].getText(), tReplace[_p.charAt(i)].getText());
tOut.append(_p);
Above is the code I use to replace a string which I read out of a TextArea (tIn -> p), then there is a Label Array (lChar) where I store every unique char (the char value is the Array index) and I have also a TextField Array (tReplace) here I write the replace string (which can be multiple chars) for every char in lChar (the char value from the 'old' char is the Array index).
So now I want to replace every char in lChar with every char in tReplace. If i want to replace '1' with '2' and '2' with '1' for the string '12' I get '11', because in the first loop it changes it to '22' and in the next loop it changes it to '11'. BUT I only want to change every letter once as if i would write
String.valueOf(21).replace("2","1").replace("1","2");
Any ideas how to do this?
you can create an automaton for this task:
cast your String to char[] using String.getChars() and then iterate over the array, replace each char as desired.
note: if you need to replace each char with a string which its length is >1, you can use the same approach, but instead using a char[], use a StringBuilder, and for each char: if it needs to be replaced, append the replacing-string to the StringBuilder, else: append the char to the StringBuilder
sample code:
String original = "1212";
HashMap<Character, String> map = new HashMap<Character, String>();
map.put('1', "22");
map.put('2', "1");
StringBuilder sb = new StringBuilder();
for (int i =0;i<original.length();i++) {
char ch = original.charAt(i);
if (map.containsKey(ch)) {
sb.append(map.get(ch));
} else {
sb.append(ch);
}
}
System.out.println(sb);
will result in: 221221
Related
I'm stuck with a loop issue here, I'm working on a script who will receive let's say the String "geij" or "abab" and will have to turn it into a double like "6478" or "0101". I do the conversion from letter to number thanks to a two-dimensional array :
String crypt = "geij";
char twoD[][] = {{'a','b','c','d','e','f','g','h','i','j'}, {'0','1','2','3','4','5','6','7','8','9'}};
First I pass the String into a char array :
char tab[] = crypt.toCharArray();
Then I use a loop to convert from letter to number :
for(int c=0;c<tab.length;c++) {
for(int z=0;z<twoD.length;z++) {
if(tab[c] == twoD[0][z]) {
tab[c] = twoD[1][z];
}
}
Then I create a new instance of String named 'second' to turn the array into a String
String second = new String(tab);
And I turned this String into a double
double finalC = Double.parseDouble(second);
The issue is with this loop, If the String crypt is "abab", the loop will return 0101 as it is supposed to, but if the String contains any letter after "a" or "b" from the first array of the two-dimensional array, like for example the String "geij" the program will simply return "geij".
I don't understand why the program doesn't go further than b and it is starting to give me an egghead. If anyone has an idea I'll be grateful !
Here is an example of the inside of the tab array after the loop for the String "abcd" :
Indice : 0 value: 0
Indice : 1 value: 1
Indice : 2 value: c
Indice : 3 value: d
Kevin Cruijssen resolves your problem but you can more:
Use HashMap to this problem. For now, your algorithm time complexity is O(n*m) (n-base string length, m - amount of letters in the table) because you must iterate through the whole array of letters for each letter.
Using HashMap you can find the right letter in O(1). A lot faster. So now your algorithm has O(n) time complexity.
Simple example:
Map<Character, Integer> encoding = new HashMap<>();
encoding.put('a', 0);
encoding.put('b', 1);
encoding.put('c', 2);
encoding.put('d', 3);
String toEncode = "abcd";
char[] chars = toEncode.toCharArray();
StringBuilder sb = new StringBuilder();
for(char c : chars){
int newInt = encoding.getOrDefault(c, -5); //-5 is just a flag that there is no char to encode
if(newInt == -5){
continue; //or do something else, e.g throw exception;
}
sb.append(newInt);
}
System.out.println(sb.toString());
//Parse double if you want, but remember that what *Nikolas* said in the comments under your post.
//Double.parseDouble(sb.toString());
The problem is in your inner loop: twoD.length is 2, because twoD contains your two inner array of characters.
You should use twoD[0].length instead:
for(int c=0; c<tab.length; c++) {
for(int z=0; z<twoD[0].length; z++) {
...
However, since you are using all ten digits, perhaps better to use that instead:
char twoD[][] = {{'a','b','c','d','e','f','g','h','i','j'}, {'0','1','2','3','4','5','6','7','8','9'}};
int amountOfDigitsUsed = 10; // Equal to `twoD[0].length` or `twoD[1].length`.
for(int c=0; c<tab.length; c++) {
for(int z=0; z<amountOfDigitsUsed; z++) {
...
Regardless whether you use a hard-coded twoD conversion and amountOfDigits used or not. In your current implementation your twoD.length is 2, causing the issues you have right now.
Length of your twoD array is 2. Your second loop should iterate from z = 0 to twoD[0].length.
Try naming your variables meaningfully so it will be easier to find bugs like this. Also check out foreach loops so you don't have to worry about indexes. Java Maps could be better for mapping characters to numbers.
Since it seems as though in your case the characters are incrementing along with their int values, you don't need a map at all. You can cast the character to an int, and then subtract a's int value. This is a slight variation of B_Osipiuk's answer:
String toEncode = "abcd";
char[] chars = toEncode.toCharArray();
StringBuilder sb = new StringBuilder();
for(char c : chars){
int newInt = c - 'a';
if (newInt < 0 || newInt > ('j'-'a')) {
continue; //or do something else, e.g throw exception;
}
sb.append(newInt);
}
System.out.println(sb.toString());
In recent interview, I was asked to find solution for below String manipulation program.
Given a string s, represent the most frequent character with 1, the 2nd most frequent character with 01, third with 001 etc.
if String is "marrymyyyr", then output should be :
char count for each character is m:2 , a:1, r:3, y:4 highest count
number is 4 so the character with that count should be printed 1
inplace of that char, char with count 3 should be printed as 01
inplace of that char and so on.
Output : 001(m)0001(a)01(r)01(r)1(y)001(m)1(y)1(y)1(y)01(r)
I used HashMap to keep track of count for each character. then I was unable to solve the problem. I know I have to implement some mechanism to apply hashing/mapping to hashmap based on most frequent char mapped with its correspondence resultant string with combination of"1" "0" and print char with mapped resultant string instead of that char.
You said you used HashMap. If you created the map as Map<Character, AtomicInteger>, then you can update the value directly, without affecting the map.
This improves performance of the counting step of the process, but also allows you to then replace the "count" value with a value representing the number of 0's to print for a character, aka a "rank".
Example: With the counts being m:2, a:1, r:3, y:4 (from question), you would sort the list descending (y:4, r:3, m:2, a:1), then replace the counts with incrementing ranks: y:0, r:1, m:2, a:3.
If you use a LinkedHashMap, then multiple characters with equal count would be ranked in order of first appearance.
With those ranks, you can now convert the input. (The following is for any Java version. On Java 8, lambdas would reduce the code a lot. I'll leave that as an exercise for you.)
private static String test(String input) {
char[] chars = input.toCharArray();
// Collect chars with count of occurrences
Map<Character, AtomicInteger> charMap = new LinkedHashMap<>();
for (Character c : chars) {
AtomicInteger count = charMap.get(c);
if (count == null)
charMap.put(c, new AtomicInteger(1));
else
count.incrementAndGet();
}
// Sort char/count pairs by count (descending)
#SuppressWarnings("unchecked")
Entry<Character, AtomicInteger>[] charArr = charMap.entrySet().toArray(new Map.Entry[charMap.size()]);
Arrays.sort(charArr, new Comparator<Entry<Character, AtomicInteger>>() {
#Override
public int compare(Entry<Character, AtomicInteger> e1, Entry<Character, AtomicInteger> e2) {
return Integer.compare(e2.getValue().intValue(), e1.getValue().intValue()); // descending
}
});
// Replace "count" with "rank" (this updates values in charMap)
for (int i = 0; i < charArr.length; i++)
charArr[i].getValue().set(i);
// Generate result
StringBuilder buf = new StringBuilder();
for (Character c : chars) {
int rank = charMap.get(c).intValue();
while (rank-- > 0)
buf.append('0');
buf.append('1');
buf.append('(').append(c).append(')'); // Remove?
}
return buf.toString();
}
Test
System.out.println(test("marrymyyyr"));
Output
001(m)0001(a)01(r)01(r)1(y)001(m)1(y)1(y)1(y)01(r)
The phrasing of the question makes it sound like the letters should be replaced ("inplace of"). If so, comment out or delete the line marked with // Remove?
Output
00100010101100111101
If I want to create a dictionary where the user can create a custom alphabet (that still uses unicode) Is there a way to change lowercase and uppercase mapping of the characters?
Let's say I want the lowercase of 'I' to be 'ı' instead of 'i' or upperCase of 'b' to be 'P' instead of 'B' so that System.out.println("PAI".toLowerCase()); would write baı to the console.
I suppose I can create a method toLowerCase(String s) that first replaces "P" with "b"s then converts to lowercase but wouldn't that be slower when searching through a dictionary of hundreds of thousands of words?
The toLowerCase(String s) uses the locale to decide how to convert the characters, you should have to define your own locale and then, for example, load it as the default locale via Locale.setDefault(Locale) before executing the toLowerCase(String s)
No, it would not be slower because you are simply traversing through the array and not modifying the position of any object which would result in O(n). Performance wouldn't be affected, and any system should be able to handle a single conversion and then toLowerCase call easily.
You could also override the toLowerCase(String s) function to accommodate your needs. Even simpler!
This should do the trick:
import java.util.HashMap;
import java.util.Map;
class MyString {
String string;
static final Map<Character, Character> toLowerCaseMap, toUpperCaseMap;
static {
toLowerCaseMap = new HashMap<>();
toLowerCaseMap.put('I', '|');
toUpperCaseMap = new HashMap<>();
toUpperCaseMap.put('b', 'P');
}
MyString(String string) {
this.string = string;
}
String toLowerCase() {
char[] chars = string.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
chars[i] = toLowerCaseMap.containsKey(c) ? toLowerCaseMap.get(c) : Character.toLowerCase(c);
}
return new String(chars);
}
String toUpperCase() {
char[] chars = string.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
chars[i] = toUpperCaseMap.containsKey(c) ? toUpperCaseMap.get(c) : Character.toUpperCase(c);
}
return new String(chars);
}
}
Check this Answer you cannot inherits from String Class because its final, but you could create your class with your toLowerCase Method, I suggest you called diferents for maintenance.
And for the dictionary of hundreds of thousands of words....
Maybe you use a Map or HashMap with the key will be the string enter by the user and in the object you maybe save automatically the value in lowerCase, it depends of what you need.
But for get better performance I could recommend save the value in Database
Regards.
I want to loop through the alphabet with a for loop and add each letter to my HashMap
for(char alphabet = 'A'; alphabet <= 'Z';alphabet++) {
System.out.println(alphabet);
}
doesn't work for me, because my HashMap is of form
HashMap<String, HashMap<String, Student>> hm;
I need my iterator to be a string, but
for(String alphabet = 'A'; alphabet <= 'Z';alphabet++) {
System.out.println(alphabet);
}
doesn't work.
Basically, I want to do this:
for i from 'A' to 'Z' do
hm.put(i, null);
od
Any ideas?
Basically convert the char to a string, like this:
for(char alphabet = 'A'; alphabet <= 'Z';alphabet++) {
hm.put(""+alphabet, null);
}
Although ""+alphabet is not efficient as it boils down to a call to StringBuilder
The equivalent but more effective way can be
String.valueOf(alphabet)
or
Character.toString(alphabet)
which are actually the same.
You cannot assign a char to a String, or to increment a string with ++. You can iterate on the char the way you did in your first sample, and convert that char to a String, like this:
for(char letter = 'A'; letter <= 'Z'; letter++) {
String s = new String(new char[] {letter});
System.out.println(s);
}
First problem: When you work with a HashMap, you are supposed to map a key to a value. You don't just put something in a hash map. The letter you wanted to put, is it a value? Then what is the key? Is it a key? Then what is the value?
You might think that using "null" as a value is a good idea, but you should ask yourself: in that case, should I use a map at all? Maybe using a HashSet is a better idea?
The second problem is that a HashMap, like all java collections, only takes objects - both as keys and as values. If you want to use a character as a key, you could define your map as Map<Character,Map<String,Student>>, which will auto-box your character (convert it to an object of type Character) or you could convert the character to a string using
Character.toString(alphabet);
In Java 8 with Stream API, you can do this.
IntStream.rangeClosed('A', 'Z').mapToObj(var -> String.valueOf((char) var)).forEach(System.out::println);
I'm trying to write a method that removes all non alphabetic characters from a Java String[] and then convert the String to an lower case string. I've tried using regular expression to replace the occurence of all non alphabetic characters by "" .However, the output that I am getting is not able to do so. Here is the code
static String[] inputValidator(String[] line) {
for(int i = 0; i < line.length; i++) {
line[i].replaceAll("[^a-zA-Z]", "");
line[i].toLowerCase();
}
return line;
}
However if I try to supply an input that has non alphabets (say - or .) the output also consists of them, as they are not removed.
Example Input
A dog is an animal. Animals are not people.
Output that I'm getting
A
dog
is
an
animal.
Animals
are
not
people.
Output that is expected
a
dog
is
an
animal
animals
are
not
people
The problem is your changes are not being stored because Strings are immutable. Each of the method calls is returning a new String representing the change, with the current String staying the same. You just need to store the returned String back into the array.
line[i] = line[i].replaceAll("[^a-zA-Z]", "");
line[i] = line[i].toLowerCase();
Because the each method is returning a String you can chain your method calls together. This will perform the second method call on the result of the first, allowing you to do both actions in one line.
line[i] = line[i].replaceAll("[^a-zA-Z]", "").toLowerCase();
You need to assign the result of your regex back to lines[i].
for ( int i = 0; i < line.length; i++) {
line[i] = line[i].replaceAll("[^a-zA-Z]", "").toLowerCase();
}
It doesn't work because strings are immutable, you need to set a value
e.g.
line[i] = line[i].toLowerCase();
You must reassign the result of toLowerCase() and replaceAll() back to line[i], since Java String is immutable (its internal value never changes, and the methods in String class will return a new String object instead of modifying the String object).
As it already answered , just thought of sharing one more way that was not mentioned here >
str = str.replaceAll("\\P{Alnum}", "").toLowerCase();
A cool (but slightly cumbersome, if you don't like casting) way of doing what you want to do is go through the entire string, index by index, casting each result from String.charAt(index) to (byte), and then checking to see if that byte is either a) in the numeric range of lower-case alphabetic characters (a = 97 to z = 122), in which case cast it back to char and add it to a String, array, or what-have-you, or b) in the numeric range of upper-case alphabetic characters (A = 65 to Z = 90), in which case add 32 (A + 22 = 65 + 32 = 97 = a) and cast that to char and add it in. If it is in neither of those ranges, simply discard it.
You can also use Arrays.setAll for this:
Arrays.setAll(array, i -> array[i].replaceAll("[^a-zA-Z]", "").toLowerCase());
Here is working method
String name = "Joy.78#,+~'{/>";
String[] stringArray = name.split("\\W+");
StringBuilder result = new StringBuilder();
for (int i = 0; i < stringArray.length; i++) {
result.append(stringArray[i]);
}
String nameNew = result.toString();
nameNew.toLowerCase();
public static void solve(String line){
// trim to remove unwanted spaces
line= line.trim();
String[] split = line.split("\\W+");
// print using for-each
for (String s : split) {
System.out.println(s);
}