Delete next two characters in string with indexOf and map - java

i have a problem with a algorithm.
I have a Map (Each key int its a hex unicode character) and a String with unicode characters.
I want to delete the next character in the string when i found a character that exists as key in my map.
for example my map contains those keys: 0x111,0x333,0x444,0x555,0x666 and my string its:
0x111+0xffff+0x444+0xEEEEE+0x666
I want to convert it to:
0x111+0x444+0x666
I have this but this doesnt work:
private String cleanFlags(String text) {
int textLong = text.length();
for (int i = 0; i < textLong; i++) {
if (flagCountryEmojis.containsKey(text.codePointAt(text.charAt(i)))) {
text = text.replace(text.substring(i + 1, i + 2), "");
textLong-=2;
}
}
return text;
}
How can i do it this?

Since you didn't mention anything about space complexity, I went ahead and took the liberties of using an array to solve the question:
public String cleanFlags(String text){
String [] arr = text.split("+");
String newText = "";
for(int i = 0; i < arr.length; i++){
if(flagCountryEmojis.containsKey(arr[i])){
newText += arr[i];
i++; // skips the next character
}
if(i < arr.length - 1)
newText += "+";
}
return newText;
}
Not sure if this solution solves your problem, since strings are immutable anyways, and calling "replace" simply creates a new string in the background, I went ahead and created a new string for you and returned the result when it is populated correctly.
Lemme know if there is something I am missing or other restrictions that were unmentioned.

Related

Issues with char array and replacing words

I am attempting to iterate through characters for a "curse word filter", there is a config file that defines what the curse words will be replaced with. Sometimes my code is grabbing the last letter/number of the key and putting it at the end of the key string.
Tried doing this in a few different ways, the whole attempt of this is to avoid case sensitivity and find every possible attempt at beating it.
here's an example of it breaking - http://prntscr.com/nqyirl
public void onChat(AsyncPlayerChatEvent event)
{
String originalMessage = event.getMessage();
ArrayList<String> swearWords = new ArrayList<>();
for (String key : getConfig().getConfigurationSection("replace-words").getKeys(false))
swearWords.add(key);
ArrayList<Character> charArrayList = new ArrayList<>();
for (char c : originalMessage.toCharArray())
charArrayList.add(c);
for (String swearWord : swearWords)
{
Bukkit.broadcastMessage(swearWord);
int startIndex;
if ((startIndex = originalMessage.toLowerCase().indexOf(swearWord)) != -1)
{
int endIndex = startIndex + swearWord.length();
for (int i = startIndex; i < endIndex; i++)
{
charArrayList.remove(startIndex);
charArrayList.trimToSize();
}
char[] replaceWith = getConfig().getString("replace-words." + swearWord).toCharArray();
Bukkit.broadcastMessage(new String(replaceWith));
for (int i = 0; i < replaceWith.length; i++) {
char c = replaceWith[i];
charArrayList.add(startIndex + i, c);
}
}
}
final char[] array = new char[charArrayList.size()];
for (int i = 0; i < array.length; i++)
array[i] = charArrayList.get(i);
event.setMessage(new String(array));
}
Config File -
#configurables, enjoy
replace-words:
test1234: testo22345566
It should be replacing test1234 with testo22345566, instead it adds a 4 on the end. Making it - testo223455664. Example here - http://prntscr.com/nqyirl
EDIT: I've had a break through, anything over 7 characters breaks it.
you probably just don't remove the last symbol. my guess is that changing
for
(int i = startIndex; i < endIndex; i++)
to
for
(int i = startIndex; i <= endIndex; i++)
should fix the problem
why changing it into char[]?
a String has internal a char[], but gives you much more and easier replace functions.
for example originalMessage.replaceAll("test1234","testo22345566")
would replace all test1234 occurences with testo22345566
info about that method:https://www.javatpoint.com/java-string-replaceall
this makes it possible to add regex filters instead of a one to one replace configuration. (the replaceAll function on string uses regex for its searching of occurences)
for example
#configurables, enjoy
replace-words:
(?i)test[0-9]{4}: testo22345566
would in case of the repleaceAll function on string work on all caseinsensitive values followed by 4 numbers
be aware if the swearword replacer can recreate another swearword it could be needed to pass multiple times over this replacer.
edit: modification because of some comments:
you could also just use your config, but still use the originalMessage.replaceAll(wordOfTheConfigList,replacementword)
String newMessage = originalMessage;
String inBetweenChars = "([\s\._]*)";
for (String swearWord : swearWords){
String searchWord = "(?i)"+inBetweenChars+String.join(inBetweenChars,swearWord) + inBetweenChars;
String replaceWith = getConfig().getString("replace-words." + swearWord)
newMessage = newMessage.replaceAll(searchWord,replaceWith))
}
event.setMessage(newMessage);
with this answer you can only use normal text in the config, so no [0-9] or other regex features, as this would result in strange [\s0\s-\s9\s] kinda things (wont work) but as you weren't using regex in that config I hope that's not a real problem.

split a string when there is a change in character without a regular expression

There is a way to split a string into repeating characters using a regex function but I want to do it without using it.
for example, given a string like: "EE B" my output will be an array of strings e.g
{"EE", " ", "B"}
my approach is:
given a string I will first find the number of unique characters in a string so I know the size of the array. Then I will change the string to an array of characters. Then I will check if the next character is the same or not. if it is the same then append them together if not begin a new string.
my code so far..
String myinput = "EE B";
char[] cinput = new char[myinput.length()];
cinput = myinput.toCharArray(); //turn string to array of characters
int uniquecha = myinput.length();
for (int i = 0; i < cinput.length; i++) {
if (i != myinput.indexOf(cinput[i])) {
uniquecha--;
} //this should give me the number of unique characters
String[] returninput = new String[uniquecha];
Arrays.fill(returninput, "");
for (int i = 0; i < uniquecha; i++) {
returninput[i] = "" + myinput.charAt(i);
for (int j = 0; j < myinput.length - 1; j++) {
if (myinput.charAt(j) == myinput.charAt(j + 1)) {
returninput[j] += myinput.charAt(j + 1);
} else {
break;
}
}
} return returninput;
but there is something wrong with the second part as I cant figure out why it is not beginning a new string when the character changes.
You question says that you don't want to use regex, but I see no reason for that requirement, other than this is maybe homework. If you are open to using regex here, then there is a one line solution which splits your input string on the following pattern:
(?<=\S)(?=\s)|(?<=\s)(?=\S)
This pattern uses lookarounds to split whenever what precedes is a non whitespace character and what proceeds is a whitespace character, or vice-versa.
String input = "EE B";
String[] parts = input.split("(?<=\\S)(?=\\s)|(?<=\\s)(?=\\S)");
System.out.println(Arrays.toString(parts));
[EE, , B]
^^ a single space character in the middle
Demo
If I understood correctly, you want to split the characters in a string so that similar-consecutive characters stay together. If that's the case, here is how I would do it:
public static ArrayList<String> splitString(String str)
{
ArrayList<String> output = new ArrayList<>();
String combo = "";
//iterates through all the characters in the input
for(char c: str.toCharArray()) {
//check if the current char is equal to the last added char
if(combo.length() > 0 && c != combo.charAt(combo.length() - 1)) {
output.add(combo);
combo = "";
}
combo += c;
}
output.add(combo); //adds the last character
return output;
}
Note that instead of using an array (has a fixed size) to store the output, I used an ArrayList, which has a variable size. Also, instead of checking the next character for equality with the current one, I preferred to use the last character for that. The variable combo is used to temporarily store the characters before they go to output.
Now, here is one way to print the result following your guidelines:
public static void main(String[] args)
{
String input = "EEEE BCD DdA";
ArrayList<String> output = splitString(input);
System.out.print("[");
for(int i = 0; i < output.size(); i++) {
System.out.print("\"" + output.get(i) + "\"");
if(i != output.size()-1)
System.out.print(", ");
}
System.out.println("]");
}
The output when running the above code will be:
["EEEE", " ", "B", "C", "D", " ", "D", "d", "A"]

How to reverse a String after a comma and then print the 1st half of the String Java

For example String grdwe,erwd becomes dwregrdwe
I have most of the code I just have trouble accessing all of ch1 and ch2 in my code after my for loop in my method I think I have to add all the elements to ch1 and ch2 into two separate arrays of characters but I wouldn't know what to initially initialize the array to it only reads 1 element I want to access all elements and then concat them. I'm stumped.
And I'd prefer to avoid Stringbuilder if possible
public class reverseStringAfterAComma{
public void reverseMethod(String word){
char ch1 = ' ';
char ch2 = ' ';
for(int a=0; a<word.length(); a++)
{
if(word.charAt(a)==',')
{
for(int i=word.length()-1; i>a; i--)
{
ch1 = word.charAt(i);
System.out.print(ch1);
}
for (int j=0; j<a; j++)
{
ch2 = word.charAt(j);
System.out.print(ch2);
}
}
}
//System.out.print("\n"+ch1);
//System.out.print("\n"+ch2);
}
public static void main(String []args){
reverseStringAfterAComma rsac = new reverseStringAfterAComma();
String str="grdwe,erwd";
rsac.reverseMethod(str);
}
}
You can use string builder as described here:
First split the string using:
String[] splitString = yourString.split(",");
Then reverse the second part of the string using this:
splitString[1] = new StringBuilder(splitString[1]).reverse().toString();
then append the two sections like so:
String final = splitString[1] + splitString[0];
And if you want to print it just do:
System.out.print(final);
The final code would be:
String[] splitString = yourString.split(",");
splitString[1] = new StringBuilder(splitString[1]).reverse().toString();
String final = splitString[1] + splitString[0];
System.out.print(final);
Then, since you are using stringbuilder all you need to do extra, is import it by putting this at the top of your code:
import java.lang.StringBuilder;
It appears you currently have working code, but are looking to print/save the value outside of the for loops. Just set a variable before you enter the loops, and concatenate the chars in each loop:
String result = "";
for (int a = 0; a < word.length(); a++) {
if (word.charAt(a) == ',') {
for (int i = word.length() - 1; i > a; i--) {
ch1 = word.charAt(i);
result += ch1;
}
for (int j = 0; j < a; j++) {
ch2 = word.charAt(j);
result += ch2;
}
}
}
System.out.println(result);
Demo
Let propose a solution that doesn't use a StringBuilder
You should knoz there is no correct reason not to use that class since this is well tested
The first step would be to split your String on the first comma found (I assumed, in case there is more than one, that the rest are part of the text to reverse). To do that, we can you String.split(String regex, int limit).
The limit is define like this
If the limit n is greater than zero then the pattern will be applied at most n - 1 times, the array's length will be no greater than n and the array's last entry will contain all input beyond the last matched delimiter.
If n is non-positive then the pattern will be applied as many times as possible and the array can have any length.
If n is zero then the pattern will be applied as many times as possible, the array can have any length, and trailing empty strings will be discarded.
Example :
"foobar".split(",", 2) // {"foobar"}
"foo,bar".split(",", 2) // {"foo", "bar"}
"foo,bar,far".split(",", 2) // {"foo", "bar,far"}
So this could be used at our advantage here :
String text = "Jake, ma I ,dlrow olleh";
String[] splittedText = text.split( ",", 2 ); //will give a maximum of a 2 length array
Know, we just need to reverse the second array if it exists, using the simplest algorithm.
String result;
if ( splittedText.length == 2 ) { //A comma was found
char[] toReverse = splittedText[1].toCharArray(); //get the char array to revese
int start = 0;
int end = toReverse.length - 1;
while ( start < end ) { //iterate until needed
char tmp = toReverse[start];
toReverse[start] = toReverse[end];
toReverse[end] = tmp;
start++; //step forward
end--; //step back
}
result = new String( toReverse ) + splittedText[0];
}
This was the part that should be done with a StringBuilder using
if ( splittedText.length == 2 ){
result = new StringBuilder(splittedText[1]).reverse().toString() + splittedText[0];
}
And if there is only one cell, the result is the same as the original text
else { //No comma found, just take the original text
result = text;
}
Then we just need to print the result
System.out.println( result );
hello world, I am Jake

Is converting to String the most succinct way to remove the last comma in output in java?

So basically this is how my code looked like
public static void printPrime(int[] arr)
{
int len = arr.length;
for(int i = 0; i < len; i++)
{
int c = countFactor(arr[i]);
if(c == 2)
{
System.out.print(arr[i] + ",");
}
}
}
So the output did have the 'comma' in the end. I tried looking around to remove the last comma some answers say to print last element separately but that can only happen when output depends on the for loop and not the if condition.
But as you can see I don't know how many elements I am going to get from the if condition. Only two things I can think of, to add another loop or use String then substr to output.
So I converted it to String
public static void printPrime(int[] arr)
{
int len = arr.length;
String str = "";
for(int i = 0; i < len; i++)
{
int c = countFactor(arr[i]);
if(c == 2)
{
str = str + arr[i] + ",";
}
}
str = str.substring(0, str.length()-1);
System.out.println(str);
}
My question is about knowing the optimum way (converting to string then substringing it?) for similar questions or could there be a better way as well? That I seem to be missing.
You don't have to construct a string. Consider the following slight tweaks:
public static void printPrime(int[] arr)
{
int len = arr.length;
String sep = ""; // HERE
for(int i = 0; i < len; i++)
{
int c = countFactor(arr[i]);
if(c == 2)
{
System.out.print(sep); // HERE
sep = ",";
System.out.print(arr[i]);
}
}
}
Print the delimiter first, and store its value in a variable: the first time it's printed, it will print the empty string. Thereafter, it prints the comma.
Whatever means you use should operate correctly for an empty array (length 0), a singleton array (length 1) and a long array (a large length).
Adding the comma then removing it requires special case handling for the empty array case. So you must have conditional code (an if statement) whatever you do.

Filter bad words | java 'replace'

In an attempt to filter the bad words, I found the 'replace' function in java is not as handy as intended.
Please find below the code :
Eg : consider the word 'abcde' and i want to filter it to 'a***e'.
String test = "abcde";
for (int i = 1; i < sdf.length() - 1; i++) {
test= test.replace(test.charAt(i), '*');
}
System.out.print(test);
Output : a***e
But if the String is String test = "bbcde";, the output is ****e. It seems, if the word has repetitive letters(as in here), the replace function replaces the repetitive letters
too.
Why is it so? I want to filter the words excluding the first and last letter.
That is because String.replace(char, char) replaces all occurrences of the first character (according to its Javadoc).
What you want is probably more like this:
char[] word = test.toCharArray();
for (int i = 1; i < word.lengh - 1; i++) { // make sure to start at second char, and end at one-but-last char
word[i] = '*';
}
System.out.println(String.copyValueOf(word));
since String.replace(char, char) replaces all occurrences of specified char, this would be a better approach for your requirement:
String test = "abcde";
String replacement = "";
for (int i = 0; i < sdf.length(); i++) {
replacement += "*";
}
test= test.replace(sdf, replacement );
System.out.print(test);
It seems, if the word has repetitive letters(as in here), the replace function replaces the repetitive letters too. Why is it so?
Why? Because that's just how it works, exactly as the API documentation of String.replace(char oldChar, char newChar) says:
Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar.
If you just want to replace the content of the string by the first letter, some asterisks and the last letter, then you don't need to use replace at all.
String test = "abcde";
if (test.length() >= 1) {
StringBuilder result = new StringBuilder();
result.append(test.charAt(0));
for (int i = 0; i < test.length() - 2; ++i) {
result.append('*');
}
result.append(test.charAt(test.length() - 1));
test = result.toString();
}
System.out.println(test);
public static void main(String[] args) {
String test = "bbcde";
String output = String.valueOf(test.charAt(0));
for (int i = 1; i < test.length() - 1; i++) {
output = output + "*";
}
output = output + String.valueOf(test.charAt(test.length() - 1));
System.out.print(output);
}
You should use the replaceAll-Function:
Link
With this you can replace all times you find a given substring in a string (f.e. "abcde") and replace all these with another string (f.e. "a***e").
String test = "abcde";
String replacement = "";
for (int i = 0; i < test.length(); i++) {
if (i==0 || i==test.length()-1){
replacement += test.charAt(i);
} else {
replacement += "*";
}
}
sdf = sdf.replaceAll(test, replacement);
System.out.print(test);

Categories

Resources