I want to add "OB" before every vowel.
Sample input: "THIS IS A TEST"
Sample output: "THOBIS OBIS OBA TOBEST"
I have no idea why my code doesn't work:
public static String obify(String test) {
int x = 0;
while (x != -1) {
if (test.charAt(x) == 'A' || test.charAt(x) == 'E' || test.charAt(x) == 'I' || test.charAt(x) == 'O' || test.charAt(x) == 'U') {
test = test.replace(test.substring(x, x+1), "ob" + test.substring(x, x+1));
x += 3;
} else {
x++;
}
if (x >= test.length() - 1) {
x = -1;
}
}
return test;
}
Perfect scenario for a simple regex
String foo = "hEllo what's up?";
String rep = foo.replaceAll("(?i)([aeiou])", "OB$1");
System.out.println(rep);
You should replace
test = test.replace(test.substring(x, x+1), "ob" + test.substring(x, x+1));
with
test = test.substring(0, x) +
"ob" +
test.substring(x, x + 1) +
test.substring(x + 1);
Your problem is that replace act on all occurrences of its first parameter.
When you have "THobIS IS A TEST" and try to replace marked letter you replace both "I" letter. After it you index points to completely wrong position before second "I". Sooner or later you get to it again and situation repeats.
Your problem is in replace call.
Documentaion tells that it replaces each substring with new one.
So your string grows infinitely:
after first replace it is: "THobIS obIS A TEST"
after next one is: "THobobIS obobIS A TEST"
then "THobobobIS obobobIS A TEST"
and so on...
If you change your line
test = test.replace(test.substring(x, x+1), "ob" + test.substring(x, x+1));
to
test = test.substring(0, x) + "ob" + test.substring(x);
it will do the work.
Also you can change while condition to x < test.length() and get rid of second if.
I think it is easier this way: For the word "GTREIS":
I basically take what was before and after the vowel(including the vowel) and attaching "OB"to the first part, attaching the remaining and finally replacing the original string with the modified one.
public static String obify(String s)
{
String inloc ="OB",aux="";
String start="";
int n=s.length();
int i=0;
while (i<n)
{
if(s.charAt(i)=='A'|| s.charAt(i)=='E' || s.charAt(i)=='I' || s.charAt(i)=='O'||s.charAt(i)=='U' ){
inloc ="OB";
start="";
aux=s.substring(i);//EIS
System.out.println(aux);
start=s.substring(0,i);//GTR
System.out.println(start);
start=start+inloc;//GTROB
System.out.println(start);
start=start+aux;
s=start;
i+=3;// here you have to jump over OBE for example and search the next vowel
n+=2;
} else {
i++;
}
}
return s;
}
Related
Given a random character string not including (0-9), I need to shorten the representation of that string by adding the number of consecutive characters. For e.g: ggee will result in g2e2 being displayed.
I managed to implement the program and tested it (works correctly) through various inputs. I have run into the issue where I cannot seem to understand how the character "e" is displayed given the input above.
I have traced my code multiple times but I don't see when/how "e" is displayed when "i" is 2/3.
String input = new String("ggee");
char position = input.charAt(0);
int accumulator = 1;
for (int i = 1; i < input.length(); i++)
{
// Correction. Was boolean lastIndexString = input.charAt(i) == (input.charAt(input.length() - 1));
boolean lastIndexString = i == (input.length() - 1);
if (position == input.charAt(i))
{
accumulator++;
if (lastIndexOfString)
System.out.print(accumulator); // In my mind, I should be printing
// (input.charAt(i) + "" + accumulator); here
}
else //(position != input.charAt(i))
{
if (accumulator > 1)
{
System.out.print(position + "" + accumulator);
}
else
{
System.out.print(position + "");
}
position = input.charAt(i);
accumulator = 1;
if (lastIndexOfString)
System.out.print(input.charAt(i)); // This is always printing when
// I am at the last index of my string,
// even ignoring my condition of
// (position == input.charAt(i))
}
}
In Java 9+, using regular expression to find consecutive characters, the following will do it:
static String shorten(String input) {
return Pattern.compile("(.)\\1+").matcher(input)
.replaceAll(r -> r.group(1) + r.group().length());
}
Test
System.out.println(shorten("ggggeecaaaaaaaaaaaa"));
System.out.println(shorten("ggggee😀😀😀😁😁😁😁"));
Output
g4e2ca12
g4e2😀6😁8
However, as you can see, that code doesn't work if input string contains Unicode characters from the supplemental planes, such as Emoji characters.
Small modification will fix that:
static String shorten(String input) {
return Pattern.compile("(.)\\1+").matcher(input)
.replaceAll(r -> r.group(1) + r.group().codePointCount(0, r.group().length()));
}
Or:
static String shorten(String input) {
return Pattern.compile("(.)\\1+").matcher(input)
.replaceAll(r -> r.group(1) + input.codePointCount(r.start(), r.end()));
}
Output
g4e2ca12
g4e2😀3😁4
Basically you want each char with no of repeats.
*******************************************************************************/
public class Main
{
public static void main(String[] args) {
String s="ggggggeee";
StringBuilder s1=new
StringBuilder("") ;
;
for(int i=0;i<s.length();i++)
{
int count=0,j;
for( j=i+1;j<s.length();j++)
{
if(s.charAt(i)==s.charAt(j))
count++;
else
{
break;}
}
i=j-1;
s1=s1.append(s.charAt(i)+""+(count+1));
}
System.out.print(s1);
}}
Output
There are 3 rules in the string:
It contains either word or group (enclosed by parentheses), and group can be nested;
If there is a space between word or group, those words or groups should append with "+".
For example:
"a b" needs to be "+a +b"
"a (b c)" needs to be "+a +(+b +c)"
If there is a | between word or group, those words or groups should be surround with parentheses.
For example:
"a|b" needs to be "(a b)"
"a|b|c" needs to be "(a b c)"
Consider all the rules, here is another example:
"aa|bb|(cc|(ff gg)) hh" needs to be "+(aa bb (cc (+ff +gg))) +hh"
I have tried to use regex, stack and recursive descent parser logic, but still cannot fully solve the problem.
Could anyone please share the logic or pseudo code on this problem?
New edited:
One more important rule: vertical bar has higher precedence.
For example:
aa|bb hh cc|dd (a|b) needs to be +(aa bb) +hh +(cc dd) +((a b))
(aa dd)|bb|cc (ee ff)|(gg hh) needs to be +((+aa +dd) bb cc) +((+ee +ff) (+gg +hh))
New edited:
To solve the precedence problem, I find a way to add the parentheses before calling Sunil Dabburi's methods.
For example:
aa|bb hh cc|dd (a|b) will be (aa|bb) hh (cc|dd) (a|b)
(aa dd)|bb|cc (ee ff)|(gg hh) will be ((aa dd)|bb|cc) ((ee ff)|(gg hh))
Since the performance is not a big concern to my application, this way at least make it work for me. I guess the JavaCC tool may solve this problem beautifully. Hope someone else can continue to discuss and contribute this problem.
Here is my attempt. Based on your examples and a few that I came up with I believe it is correct under the rules. I solved this by breaking the problem up into 2 parts.
Solving the case where I assume the string only contains words or is a group with only words.
Solving words and groups by substituting child groups out, use the 1) part and recursively repeating 2) with the child groups.
private String transformString(String input) {
Stack<Pair<Integer, String>> childParams = new Stack<>();
String parsedInput = input;
int nextInt = Integer.MAX_VALUE;
Pattern pattern = Pattern.compile("\\((\\w|\\|| )+\\)");
Matcher matcher = pattern.matcher(parsedInput);
while (matcher.find()) {
nextInt--;
parsedInput = matcher.replaceFirst(String.valueOf(nextInt));
String childParam = matcher.group();
childParams.add(Pair.of(nextInt, childParam));
matcher = pattern.matcher(parsedInput);
}
parsedInput = transformBasic(parsedInput);
while (!childParams.empty()) {
Pair<Integer, String> childGroup = childParams.pop();
parsedInput = parsedInput.replace(childGroup.fst.toString(), transformBasic(childGroup.snd));
}
return parsedInput;
}
// Transform basic only handles strings that contain words. This allows us to simplify the problem
// and not have to worry about child groups or nested groups.
private String transformBasic(String input) {
String transformedBasic = input;
if (input.startsWith("(")) {
transformedBasic = input.substring(1, input.length() - 1);
}
// Append + in front of each word if there are multiple words.
if (transformedBasic.contains(" ")) {
transformedBasic = transformedBasic.replaceAll("( )|^", "$1+");
}
// Surround all words containing | with parenthesis.
transformedBasic = transformedBasic.replaceAll("([\\w]+\\|[\\w|]*[\\w]+)", "($1)");
// Replace pipes with spaces.
transformedBasic = transformedBasic.replace("|", " ");
if (input.startsWith("(") && !transformedBasic.startsWith("(")) {
transformedBasic = "(" + transformedBasic + ")";
}
return transformedBasic;
}
Verified with the following test cases:
#ParameterizedTest
#CsvSource({
"a b,+a +b",
"a (b c),+a +(+b +c)",
"a|b,(a b)",
"a|b|c,(a b c)",
"aa|bb|(cc|(ff gg)) hh,+(aa bb (cc (+ff +gg))) +hh",
"(aa(bb(cc|ee)|ff) gg),(+aa(bb(cc ee) ff) +gg)",
"(a b),(+a +b)",
"(a(c|d) b),(+a(c d) +b)",
"bb(cc|ee),bb(cc ee)",
"((a|b) (a b)|b (c|d)|e),(+(a b) +((+a +b) b) +((c d) e))"
})
void testTransformString(String input, String output) {
Assertions.assertEquals(output, transformString(input));
}
#ParameterizedTest
#CsvSource({
"a b,+a +b",
"a b c,+a +b +c",
"a|b,(a b)",
"(a b),(+a +b)",
"(a|b),(a b)",
"a|b|c,(a b c)",
"(aa|bb cc|dd),(+(aa bb) +(cc dd))",
"(aa|bb|ee cc|dd),(+(aa bb ee) +(cc dd))",
"aa|bb|cc|ff gg hh,+(aa bb cc ff) +gg +hh"
})
void testTransformBasic(String input, String output) {
Assertions.assertEquals(output, transformBasic(input));
}
I tried to solve the problem. Not sure if it works in all cases. Verified with the inputs given in the question and it worked fine.
We need to format the pipes first. That will help add necessary parentheses and spacing.
The spaces generated as part of pipe processing can interfere with actual spaces that are available in our expression. So used $ symbol to mask them.
To process spaces, its tricky as parantheses need to be processed individually. So the approach I am following is to find a set of parantheses starting from outside and going inside.
So typically we have <left_part><parantheses_code><right_part>. Now left_part can be empty, similary right_part can be empty. we need to handle such cases.
Also, if the right_part starts with a space, we need to add '+' to left_part as per space requirement.
NOTE: I am not sure what's expected of (a|b). If the result should be ((a b)) or (a b). I am going with ((a b)) purely by the definition of it.
Now here is the working code:
public class Test {
public static void main(String[] args) {
String input = "aa|bb hh cc|dd (a|b)";
String result = formatSpaces(formatPipes(input)).replaceAll("\\$", " ");
System.out.println(result);
}
private static String formatPipes(String input) {
while (true) {
char[] chars = input.toCharArray();
int pIndex = input.indexOf("|");
if (pIndex == -1) {
return input;
}
input = input.substring(0, pIndex) + '$' + input.substring(pIndex + 1);
int first = pIndex - 1;
int closeParenthesesCount = 0;
while (first >= 0) {
if (chars[first] == ')') {
closeParenthesesCount++;
}
if (chars[first] == '(') {
if (closeParenthesesCount > 0) {
closeParenthesesCount--;
}
}
if (chars[first] == ' ') {
if (closeParenthesesCount == 0) {
break;
}
}
first--;
}
String result;
if (first > 0) {
result = input.substring(0, first + 1) + "(";
} else {
result = "(";
}
int last = pIndex + 1;
int openParenthesesCount = 0;
while (last <= input.length() - 1) {
if (chars[last] == '(') {
openParenthesesCount++;
}
if (chars[last] == ')') {
if (openParenthesesCount > 0) {
openParenthesesCount--;
}
}
if (chars[last] == ' ') {
if (openParenthesesCount == 0) {
break;
}
}
last++;
}
if (last >= input.length() - 1) {
result = result + input.substring(first + 1) + ")";
} else {
result = result + input.substring(first + 1, last) + ")" + input.substring(last);
}
input = result;
}
}
private static String formatSpaces(String input) {
if (input.isEmpty()) {
return "";
}
int startIndex = input.indexOf("(");
if (startIndex == -1) {
if (input.contains(" ")) {
String result = input.replaceAll(" ", " +");
if (!result.trim().startsWith("+")) {
result = '+' + result;
}
return result;
} else {
return input;
}
}
int endIndex = startIndex + matchingCloseParenthesesIndex(input.substring(startIndex));
if (endIndex == -1) {
System.out.println("Invalid input!!!");
return "";
}
String first = "";
String last = "";
if (startIndex > 0) {
first = input.substring(0, startIndex);
}
if (endIndex < input.length() - 1) {
last = input.substring(endIndex + 1);
}
String result = formatSpaces(first);
String parenthesesStr = input.substring(startIndex + 1, endIndex);
if (last.startsWith(" ") && first.isEmpty()) {
result = result + "+";
}
result = result + "("
+ formatSpaces(parenthesesStr)
+ ")"
+ formatSpaces(last);
return result;
}
private static int matchingCloseParenthesesIndex(String input) {
int counter = 1;
char[] chars = input.toCharArray();
for (int i = 1; i < chars.length; i++) {
char ch = chars[i];
if (ch == '(') {
counter++;
} else if (ch == ')') {
counter--;
}
if (counter == 0) {
return i;
}
}
return -1;
}
}
I am a beginner coder. My code needs to display "yes" if the string input consists of 'l' + 'any character' + 'l'. For example, "uwbıclsl" should have a "yes" output because a letter is sandwiched between two l's. However, since my print statements are inside of my for loop, it displays several "yes" and "no" s. How can I fix it so that I only have 1 output(yes or no) and still have print statements instead of returns?
for (int i = 0; i < s.length(); i++) {
if ((s.charAt(i) == 'l') && (s.charAt(i + 2) == 'l')) {
System.out.print("YES");
} else
System.out.print("NO");
Better use regexes for this
System.out.println(s.matches(".*l.l.*") ? "YES" : "NO");
Do the below changes -
String result = "NO";
for (int i = 0; i < s.length(); i++) {
if ((s.charAt(i) == 'l') && (s.charAt(i + 2) == 'l')) {
result = "YES";
}
}
System.out.println(result);
Note - You dont need else block now, also you need to handle StringIndexOutOfBoundsException exception in your if statement, hope you can resolve this.
If you need to print Yes/No just once, try the below. Even if multiple matches, it just says Yes once. Also fixed "for" loop end length to (length()-2) to avoid Exception. Comment if you have any questions or this is not an expected solution.
boolean isFound = false;
for (int i = 0; i < s.length()-2; i++) {
if ((s.charAt(i) == 'l') && (s.charAt(i + 2) == 'l')) {
isFound = true;
}
}
System.out.println (isFound?"YES":"NO");
You also can drop the cycle and use regex
String s = "uwbıclsl".matches(".*(l.l).*") ? "yes" : "no";
System.out.println("s = " + s);
How about slightly modifying your current code to be in a separate method and subsequently returning "Yes" if you have found two l's separated by another char, since you do not need to carry on checking the rest of the string:
class Main {
public static void main(String[] args) {
String str = "uwbıclsl";
System.out.println(charBetweenTwoLs(str));
String str2 = "abclol";
System.out.println(charBetweenTwoLs(str2));
}
static String charBetweenTwoLs(String str) {
for (int i = 0; i < str.length() - 2; i++) { // Note the - 2 since you are checking on each iteration 2 characters ahead.
if (str.charAt(i) == 'l' && str.charAt(i+2) == 'l') {
return "Yes";
}
}
return "No"; // return No if two 'l' characters were not found sperated by another character.
}
}
Output:
Yes
Yes
The overall goal of what I'm trying to do is to compare a string to index 0 of an array (that is held within an arraylist), and if the strings are the same (ignoring case), call a method that matches the case of the string to the translated word (held at index 1 of the array inside an arraylist). When I run this code and I print out the contents of my translated arraylist, I get all "no match" characters. I'm assuming this is because I'm not accessing the index I want in the correct manner. Please help!
public static String translate(String word, ArrayList<String[]> wordList) {
if (word == "." || word == "!" || word == ";" || word == ":") {
return word;
}
for (int i = 0; i < wordList.size(); i++) {
String origWord = wordList.get(i)[0];
String transWord = wordList.get(i)[1];
if (word.equalsIgnoreCase(origWord)) { //FIXME may need to change if you need to switch from translated to original
String translated = matchCase(word, transWord);
return translated;
}
}
String noMatch = Character.toString(Config.LINE_CHAR);
return noMatch;
}
Sample Data and expected result
word = "hello"
wordList.get(i)[0] = "Hello"
wordList.get(i)[1] = "Hola"
(word and wordList.get(i)[0] match, so the next step is executed)
match case method is called and returns the translated word with the same case as the original word ->
translated = "hola"
returns the translated word.
(the for loop iterates through the entire wordList until it finds a match, then it calls the translate method)
**
Match Case's Code
public static String matchCase(String template, String original) {
String matched = "";
if (template.length() > original.length()) {
for (int i = 1; i <= original.length(); i++) {
if (template.charAt(i-1) >= 'a' && template.charAt(i-1) <= 'z') {
if (i == original.length()) {
matched += original.substring(original.length() - 1).toLowerCase();
}
else {
matched += original.substring((i-1), i).toLowerCase();
}
}
else if (template.charAt(i-1) >= 'A' && template.charAt(i-1) <= 'Z') {
if (i == original.length()) {
matched += original.substring(original.length() - 1).toUpperCase();
}
else {
matched += original.substring((i-1), i).toUpperCase();
}
}
}
return matched;
}
else if (template.length() < original.length()) {
int o;
original.toLowerCase();
for (int i = 1; i <= template.length(); i++) {
if (template.charAt(i-1) >= 'a' && template.charAt(i-1) <= 'z') {
if (i == template.length()) {
matched += original.substring(original.length() - 1).toLowerCase();
}
else {
matched += original.substring((i-1), i).toLowerCase();
}
}
else if (template.charAt(i-1) >= 'A' && template.charAt(i-1) <= 'Z') {
if (i == template.length()) {
matched += original.substring(original.length() - 1).toUpperCase();
}
else {
matched += original.substring((i-1), i).toUpperCase();
}
}
String newMatched = matched + original.substring(i, original.length() - 1);
matched = newMatched;
newMatched = "";
}
return matched;
}
return original;
}
I have tested your code and it works rather well with the example you have provided. I cannot help for your bug.
There are however some bugs to notify and improvement to suggest:
matchCase fails when template is shorter than the translated word.
Never compare strings with ==. Use the equals method and look why .
This is not really important but why is noMatch always computed. Why don't you declare it as a constant once?
public static final String NO_MATCH = String.valueOf(Config.LINE_CHAR);
More importantly I think that matchCase is not really pertinent by design and is over complicated. I think that You should just determine if the word to translate is all lower case or upper case or with the first letter in uppercase and the following letters in lower case. What you do (comparing the case letter by letter) is not really pertinent when the length is different.
When you consider a single character, use charAt instead of substringit is simpler and faster.
You also might have a look a regex to analyze your Strings.
Have you considered Maps for your translation lookup?
...
I'd like to check if some character is between 2 other chars.
For example, given the following String:
String myString = "Hello, my name is 'Tesda', and this is 'ASDfs'."
I want to check if the 'S' in "ASDfs" is between '' or not, also keeping in mind I want to check every '', not jump directly to the second ''.
I've tried a silly code (I'm not familiar with this at all, as I didn't need it until now), which is:
boolean isBetween;
if (!MyString.substring(MyString.indexOf("'"), MyString.indexOf("'")).contains("S"))
isBetween = true;
Well, this didn't work and I don't understand how to make it perfectly.
Also, I want to replace that S with another letter, but I want only between the '', not the one after "my name is", I thought about getting the index of the letter, if it's inside '', then replace that letter in that specific index, is that possible?
Using the provided answer, I've made the following code ( which why i posted this question for ) :
String NewText = "Hello, My NAme is 'Ba', i'm from 'LA' ";
boolean contains = false;
int indexOfS = -1;
String MyString_temp = NewText;
while (MyString_temp.length() >= 0) {
int first = MyString_temp.indexOf("\'");
if(first == -1)
{
break;
}
int second = MyString_temp.substring((first + 1)).indexOf("\'");
second = second + first + 1;
if(second == -1)
{
break;
}
contains = MyString_temp.substring(first,second).contains("A");
if (contains) {
break;
}
MyString_temp = MyString_temp.substring((second + 1));
}
Log.i("ResultTest","Index is: " + indexOfS + " - Text is: " + MyString_temp);
if(!contains){
Log.i("ResultTest", "Yes " + i);
Log.i("ResultTest","TeF: " +NewText.replace(NewText.substring(indexOfS,indexOfS+1),"Test"));
} else
Log.i("ResultTest", "No " + i);
Output
Index is: -1 - the text here ..
Failed to output, invalid index
Consider using regular expressions. Your example could be as simple as
MyString.matches("\'S\'");
EDIT: Updated answer for updated question: Your initial code block looked like it might have done the trick, however you must remember that indexOf() only returns the first occurence of what you need. This could work:
String MyString_temp = MyString;
String lookingFor = "S";
String separator = "\'";
boolean contains = false;
int indexOfLooking = -1;
while (MyString_temp.length() >= 0) {
int first = MyString_temp.indexOf(separator);
if(first == -1) {
break;
}
int second = MyString_temp.substring(first + 1).indexOf(separator);
second += first + 1;
if(second == -1) {
break;
}
indexOfLooking = MyString_temp.substring(first, second).indexOf(lookingFor);
contains = (indexOfLooking >= 0)
if (contains) {
break;
}
MyString_temp = MyString_temp.substring(second + 1);
}
After the while loop, contains has your answer, and indexOfLooking has the location of S.
With Apache Commons you can use the following method:
StringUtils.substringBetween(str, "'");
to get an String[] with all results use this:
StringUtils.substringsBetween(str, "'", "'");