Issues with char array and replacing words - java

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.

Related

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.

Compare two arrayList and get longest matching String

So what I'm trying to do is get two text files and to return the longest matching string in both. I put both textfiles in arraylist and seperated them by everyword. This is my code so far, but I'm just wondering how I would return the longest String and not just the first one found.
for(int i = 0; i < file1Words.size(); i++)
{
for(int j = 0; j < file2Words.size(); j++)
{
if(file1Words.get(i).equals(file2Words.get(j)))
{
matchingString += file1Words.get(i) + " ";
}
}
}
String longest = "";
for (String s1: file1Words)
for (String s2: file2Words)
if (s1.length() > longest.length() && s1.equals(s2)) longest = s1;
if you are looking for performance in time and space,when compared to above replies, you can use below code.
System.out.println("Start time :"+System.currentTimeMillis());
String longestMatch="";
for(int i = 0; i < file1Words.size(); i++) {
if(file1Words.get(i).length()>longestMatch.length()){
for(int j = 0; j < file2Words.size(); j++) {
String w = file1Words.get(i);
if (w.length() > longestMatch.length() && w.equals(file2Words.get(j)))
longestMatch = w;
}
}
System.out.println("End time :"+System.currentTimeMillis());
I'm not going to give you the code but I'll help you with the main ides...
You will need a new string variable "curLargestString" to keep track of what is currently the largest string. Declare this outside of your for loops. Now, for every time you get two matching words, compare the size of the matching word to the size of the size of the word in "curLargestString". If the new matching word is larger, than set "curLargestString" to the new word. Then, after your for loop have run, return curLargestString.
One more note, be sure to initialize curLargestString with an empty string. This will prevent an error when you call the size function on it after you get your first matching word
Assuming, your files are small enough to fit in memory, sort them both with a custom comparator, that puts longer strings before shorter ones, and otherwise sorts lexicographically.
Then go through both files in order, advancing only one index at a time (teh one, pointing to the "smallest" entry of two), and return the first match.
You can use following code:
String matchingString = "";
Set intersection = new HashSet(file1Words);
intersection.retainAll(file2Words)
for(String word: intersection)
if(word.length() > matchingString.size())
matchingString = word;
private String getLongestString(List<String> list1, List<String> list2) {
String longestString = null;
for (String list1String : list1) {
if (list1String.size() > longestString.size()) {
for (String list2String : list2) {
if (list1String.equals(list2String)) {
longestString = list1String;
}
}
}
}
return longestString;
}

Delete next two characters in string with indexOf and map

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.

Counting the number of unique letters in a string

I have to write code that counts how many unique letters are in a string:
e.g
"aabbcdefff"
This will return 6 as there are 6 different letters in the string. Currently I have the code:
String letters = ("aabbcdefff");
char temp = ' ';
for (int i = 0; i < letters.length(); i++){
temp = inp.charAt(i);
if (temp != ' ') { //doesnt count spaces as letters
alphabetSize = alphabetSize+1;
for (int j = 0; j < inp.length(); j++){
tempInp = tempInp.replace(temp,' ');
}
}
}
The idea of this code is that it should when detecting a letter, replace all instances of it with a space. When i run this code however, it just gives me the length of the string. What am i doing wrong? Is there another more elegant way to do this?
Thanks for your help.
You are fine by just using a Set.
Loop over your string, and add each letter to your set. afterwards, check length of your set, and your done.
It's a one-liner with Java 8 streaming API:
long numberOfDistinctChars = s.chars().distinct().count()
You can easily find it using Linq service.
Please add using System.Linq; Namespace.
string str = "TestTest";
int cnt = str.ToLower().ToCharArray().Where(w => w != ' ').Distinct().Count();
You can do it easily by using Java collection (Set).
Set<Character> result = new HashSet<Character>();
String letters = ("aabbcdefff");
for (int i = 0; i < letters.length(); i++){
result.add(letters.charAt(i));
}
Your final result is in result set and it is always unique.
Reference: http://docs.oracle.com/javase/7/docs/api/java/util/Set.html
Thanks.
One way of doing this would be converting the string to an array and then using the following method:
String s = "aabbcdefff";
char[] charArray = s.toCharArray();
ArrayList<Character> al = new ArrayList<Character>();
for(char c : charArray){
if(al.contains(c)){
al.remove((Character)c);
}else{
al.add(c);
}
}
What ever is left in the array list 'al' are duplicates. The advantage of this method is that it has O(n) runtime

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