For this Kata, i am given random function names in the PEP8 format and i am to convert them to camelCase.
(input)get_speed == (output)getSpeed ....
(input)set_distance == (output)setDistance
I have a understanding on one way of doing this written in pseudo-code:
loop through the word,
if the letter is an underscore
then delete the underscore
then get the next letter and change to a uppercase
endIf
endLoop
return the resultant word
But im unsure the best way of doing this, would it be more efficient to create a char array and loop through the element and then when it comes to finding an underscore delete that element and get the next index and change to uppercase.
Or would it be better to use recursion:
function camelCase takes a string
if the length of the string is 0,
then return the string
endIf
if the character is a underscore
then change to nothing,
then find next character and change to uppercase
return the string taking away the character
endIf
finally return the function taking the first character away
Any thoughts please, looking for a good efficient way of handing this problem. Thanks :)
I would go with this:
divide given String by underscore to array
from second word until end take first letter and convert it to uppercase
join to one word
This will work in O(n) (go through all names 3 time). For first case, use this function:
str.split("_");
for uppercase use this:
String newName = substring(0, 1).toUpperCase() + stre.substring(1);
But make sure you check size of the string first...
Edited - added implementation
It would look like this:
public String camelCase(String str) {
if (str == null ||str.trim().length() == 0) return str;
String[] split = str.split("_");
String newStr = split[0];
for (int i = 1; i < split.length; i++) {
newStr += split[i].substring(0, 1).toUpperCase() + split[i].substring(1);
}
return newStr;
}
for inputs:
"test"
"test_me"
"test_me_twice"
it returns:
"test"
"testMe"
"testMeTwice"
It would be simpler to iterate over the string instead of recursing.
String pep8 = "do_it_again";
StringBuilder camelCase = new StringBuilder();
for(int i = 0, l = pep8.length(); i < l; ++i) {
if(pep8.charAt(i) == '_' && (i + 1) < l) {
camelCase.append(Character.toUpperCase(pep8.charAt(++i)));
} else {
camelCase.append(pep8.charAt(i));
}
}
System.out.println(camelCase.toString()); // prints doItAgain
The question you pose is whether to use an iterative or a recursive approach. For this case I'd go for the recursive approach because it's straightforward, easy to understand doesn't require much resources (only one array, no new stackframe etc), though that doesn't really matter for this example.
Recursion is good for divide-and-conquer problems, but I don't see that fitting the case well, although it's possible.
An iterative implementation of the algorithm you described could look like the following:
StringBuilder buf = new StringBuilder(input);
for(int i = 0; i < buf.length(); i++){
if(buf.charAt(i) == '_'){
buf.deleteCharAt(i);
if(i != buf.length()){ //check fo EOL
buf.setCharAt(i, Character.toUpperCase(buf.charAt(i)));
}
}
}
return buf.toString();
The check for the EOL is not part of the given algorithm and could be ommitted, if the input string never ends with '_'
Related
I need to replace first and middle char in string but without builder and etc, just with replace but idk how to make it.
String char = JOptionPane.showInputDialog(null, "Input string with more than 3 char");
if (char.length() < 3) {
JOptionPane.showMessageDialog(null, "Wrong input");
I just made this code and that is it, idk how to continue.
Example: input - pniut
I tried with smth like char.length / 2 but cant.
You can convert your string to a character array, and then swap the characters at 0 and middle position. Then convert the array back to String. e.g. I hard coded 2 here but like you mentioned in comments, you will need to figure out the character at the middle position.
String str = "input";
int mid = -1;
if(str.length() % 2 == 0) {
str.length() / 2 - 1
} else {
str.length() / 2;
}
char[] arr = str.toCharArray();
char temp = '0';
temp = arr[0];
arr[0] = arr[mid];
arr[mid] = temp;
String.valueOf(arr);
The value of the middle character, you will need to find out, like you said in the comments.
Since String objects are immutable, converting the original String to a char[] via toCharArray(), replace the characters, then making a new String from char[] via the String(char[]) constructor would work as shown below:
char[] c = character.toCharArray();
// Change characters at desired indicies
c[0] = 'p'; // first character
c[character.length()/2] = 'i'; // approximate middle character
String newString = new String(c);
System.out.println(newString); // "pniut"
Simple answer: not possible (for generic cases).
Meaning: all variants of String.replace() work by replacing one thing with another. There is no notion of using an index anywhere. So you can't say "replace index 1 with A" and "index 3 with B".
The simply solution is to push the string into a char[], to then swap/replace individual characters via index.
I'm betting the goal of the lesson is to learn how to use the API. So would start here Java API. Go to java.lang.String.
I would focus on the .toCharArray() method and the constructor that takes a char[] as an argument. You need to do this because a String is immutable, and cannot be changed. A char[], however can be altered, allowing you to modify the first and middle slots. You can then take your altered array and convert it back into a String.
I've been working on a Java program to convert English words to Pig Latin. I've done all the basic rules such as appending -ay, -way, etc., and special cases like question -> estionquay, rhyme -> ymerhay, and I also dealt with capitalization (Thomas -> Omasthay). However, I have one problem that I can't seem to solve: I need to preserve before-and-after punctuation. For example, What? -> Atwhay? Oh!->Ohway! "hello" -> "ellohay" and "Hello!" -> "Ellohay!" This is not a duplicate by the way, I've checked tons of pig latin questions and I cannot seem to figure out how to do it.
Here is my code so far (I've removed all the punctuation but can't figure out how to put it back in):
public static String scrub(String s)
{
String punct = ".,?!:;\"(){}[]<>";
String temp = "";
String pigged = "";
int index, index1, index2, index3 = 0;
for(int i = 0; i < s.length(); i++)
{
if(punct.indexOf(s.charAt(i)) == -1) //if s has no punctuation
{
temp+= s.charAt(i);
}
} //temp equals word without punctuation
pigged = pig(temp); //pig is the piglatin-translator method that I have already written,
//didn't want to put it here because it's almost 200 lines
for(int x = 0; x < s.length(); x++)
{
if(s.indexOf(punct)!= -1)//punctuation exists
{
index = x;
}
}
}
I get that in theory you could search the string for punctuation and that it should be near the beginning or end, so you would have to store the index and replace it after it is "piglatenized", but I keep getting confused about the for loop part. if you do index = x inside the for-loop, you're just replacing index every time the loop runs.
Help would be appreciated greatly! Also, please keep in mind I can't use shortcuts, I can use String methods and such but not things like Collections or ArrayLists (not that you'd need them here), I have to reinvent the wheel, basically. By the way, in case it wasn't clear, I already have the translating-to-piglatin thing down. I only need to preserve the punctuation before and after translating.
If you are allowed to use regular expressions, you can use the following code.
String pigSentence(String sentence) {
Matcher m = Pattern.compile("\\p{L}+").matcher(sentence);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(pig(m.group()));
}
m.appendTail();
return sb.toString();
}
In plain English, the above code is:
for each word in the sentence:
replace it with pig(word)
But if regular expressions are forbidden, you can try this:
String pigSentence(String sentence) {
char[] chars = sentence.toCharArray();
int i = 0, len = chars.length;
StringBuilder sb = new StringBuilder();
while (i < len) {
while (i < len && !Character.isLetter(chars[i]))
sb.append(chars[i++]);
int wordStart = i;
while (i < len && Character.isLetter(chars[i]))
i++;
int wordEnd = i;
if (wordStart != wordEnd) {
String word = sentence.substring(wordStart, wordEnd - wordStart);
sb.append(pig(word));
}
}
return sb.toString();
}
What you need to do is: remove punctuation if it exists, convert to pig latin, add punctuation back.
Assuming punctuation is always and the end of the string, You can check for punctuation with the following:
String punctuation = "";
for (int i = str.length() - 1; i > 0; i--) {
if (!Character.isLetter(str.charAt(i))) {
punctuation = str.charAt(i) + punctuation;
} else {
break; // Found all punctuation
}
}
str = str.substring(0, str.length() - punctuation.length()); // Remove punctuation
// Convert str to pig latin
// Append punctuation to str
I'd find it troublesome to handle punctuation separate from the translation. For punctuation at the very beginning or very end, you can save them and tag them back on after translating.
But if you remove the punctuations from the middle of the word, it will be rather difficult to replace them back to their correct location. Their indices change from the original word to the pigged word, and by a variable amount. (For some a random example, consider "Hel'lo" and "Quest'ion". The apostrophe shifts left by either 1 or 2, and you won't know which.)
How does your translation method handle punctuation? Do you really need to remove all punctuation before passing it to the translator? I'd suggest having your pigging method handle at least the punctuation in the middle of the word.
I was working on some string formatting, and I was curious if I was doing it the most efficient way.
Assume I have a String Array:
String ArrayOne[] = {"/test/" , "/this/is/test" , "/that/is/" "/random/words" }
I want the result Array to be
String resultArray[] = {"test", "this_is_test" , "that_is" , "random_words" }
It's quite messy and brute-force-like.
for(char c : ArrayOne[i].toCharArray()) {
if(c == '/'){
occurances[i]++;
}
}
First I count the number of "/" in each String like above and then using these counts, I find the indexOf("/") for each string and add "_" accordingly.
As you can see though, it gets very messy.
Is there a more efficient way to do this besides the brute-force way I'm doing?
Thanks!
You could use replaceAll and replace, as follows:
String resultArray[] = new String[ArrayOne.length];
for (int i = 0; i < ArrayOne.length; ++i) {
resultArray[i] = ArrayOne[i].replaceAll("^/|/$", "").replace('/', '_');
}
The replaceAll method searches the string for a match to the regex given in the first argument, and replaces each match with the text in the second argument.
Here, we use it first to remove leading and trailing slashes. We search for slashes at the start of the string (^/) or the end of the string (/$), and replace them with nothing.
Then, we replace all remaining slashes with underscores using replace.
I have some raw output that I want to clean up and make presentable but right now I go about it in a very ugly and cumbersome way, I wonder if anyone might know a clean and elegant way in which to perform the same operation.
int size = charOutput.size();
for (int i = size - 1; i >= 1; i--)
{
if(charOutput.get(i).compareTo(charOutput.get(i - 1)) == 0)
{
charOutput.remove(i);
}
}
for(int x = 0; x < charOutput.size(); x++)
{
if(charOutput.get(x) == '?')
{
charOutput.remove(x);
}
}
String firstOne = Arrays.toString(charOutput.toArray());
String secondOne = firstOne.replaceAll(",","");
String thirdOne = secondOne.substring(1, secondOne.length() - 1);
String output = thirdOne.replaceAll(" ","");
return output;
ZouZou has the right code for fixing the final few calls in your code. I have some suggestions for the for loops. I hope I got them right...
These work after you get the String represented by charOutput, using a method such as the one suggested by ZouZou.
Your first block appears to remove all repeated letters. You can use a regular expression for that:
Pattern removeRepeats = Pattern.compile("(.)\\1{1,}");
// "(.)" creates a group that matches any character and puts it into a group
// "\\1" gets converted to "\1" which is a reference to the first group, i.e. the character that "(.)" matched
// "{1,}" means "one or more"
// So the overall effect is "one or more of a single character"
To use:
removeRepeats.matcher(s).replaceAll("$1");
// This creates a Matcher that matches the regex represented by removeRepeats to the contents of s, and replaces the parts of s that match the regex represented by removeRepeats with "$1", which is a reference to the first group captured (i.e. "(.)", which is the first character matched"
To remove the question mark, just do
Pattern removeQuestionMarks = Pattern.compile("\\?");
// Because "?" is a special symbol in regex, you have to escape it with a backslash
// But since backslashes are also a special symbol, you have to escape the backslash too.
And then to use, do the same thing as was done above except with replaceAll("");
And you're done!
If you really wanted to, you can combine a lot of regex into two super-regex expressions (and one normal regex expression):
Pattern p0 = Pattern.compile("(\\[|\\]|\\,| )"); // removes brackets, commas, and spaces
Pattern p1 = Pattern.compile("(.)\\1{1,}"); // Removes duplicate characters
Pattern p2 = Pattern.compile("\\?");
String removeArrayCharacters = p0.matcher(charOutput.toString()).replaceAll("");
String removeDuplicates = p1.matcher(removeArrayCharacters).replaceAll("$1");
return p2.matcher(removeDuplicates).replaceAll("");
Use a StringBuilder and append each character you want, at the end just return myBuilder.toString();
Instead of this:
String firstOne = Arrays.toString(charOutput.toArray());
String secondOne = firstOne.replaceAll(",","");
String thirdOne = secondOne.substring(1, secondOne.length() - 1);
String output = thirdOne.replaceAll(" ","");
return output;
Simply do:
StringBuilder sb = new StringBuilder();
for(Character c : charOutput){
sb.append(c);
}
return sb.toString();
Note that you are doing a lot of unnecessary work (by iterating through the list and removing some elements). What you can actually do is just iterate one time and then if the condition fullfits your requirements (the two adjacent characters are not the same and no question mark) then append it to the StringBuilder directly.
This task could also be a job for a regular expression.
If you don't want to use Regex try this version to remove consecutive characters and '?':
int size = charOutput.size();
if (size == 1) return Character.toString((Character)charOutput.get(0));
else if (size == 0) return null;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size - 1; i++) {
Character temp = (Character)charOutput.get(i);
if (!temp.equals(charOutput.get(i+1)) && !temp.equals('?'))
sb.append(temp);
}
//for the last element
if (!charOutput.get(size-1).equals(charOutput.get(size-2))
&& !charOutput.get(size-1).equals('?'))
sb.append(charOutput.get(size-1));
return sb.toString();
For a project, I've given a sequence that the program searches for and tries to find a sequence of letters. If it finds any, it makes those sequences capitalized and prints out the line.
For instance in sequence bcdaaab when I run the program, and specify the string aa as what to find,
what should be printed is: bcdAAAb
what is being printied is: bcdAAab (notice the third a is not capped).
This is because I'm just using the replaceAll function for strings which does not ignore case. I want to know if there is any way to make it so it ignores case when I'm searching. If I can't use replaceAll at all, could someone suggest other algorithm?
The problem you're running into is that even with case-insensitive matching, it replaces the first 'aa' and then searches for the next match starting after the original replacement. Since the next position after the replacement is a single 'a' followed by a different letter, it doesn't consider it a match.
This will take care of your problem:
"bcdaaab".replaceAll("(?i)a((?=a)|(?<=a))","A");
Instead of replacing 'aa' with 'AA', use this to replace one 'a' at a time. It utilizes a lookahead and a lookbehind to basically say "is there another 'a' next to me?"
If you don't want to do that for whatever reason, you can always do a while(matcher.find(offset)) loop.
This will help you
String abc ="NewDc";
System.out.println(abc.replaceAll("(?i)dc"," Data Center."));
try this
String s1 = "bcdaaab";
String s2 = "aa";
StringBuilder sb = new StringBuilder(s1);
for (int i = 0;; i++) {
i = s1.indexOf(s2, i);
if (i == -1) {
break;
}
sb.replace(i, i + s2.length(), s2.toUpperCase());
}
System.out.println(sb);
output
bcdAAAb
In case for replacement aA result also should be bcdAAAb you can use
String s1 = "bcdaaab";
String s2 = "aA".toUpperCase();
StringBuilder sb = new StringBuilder(s1);
s1 = s1.toUpperCase();
for (int i = 0;; i++) {
i = s1.indexOf(s2, i);
if (i == -1) {
break;
}
sb.replace(i, i + s2.length(), s2.toUpperCase());
}
System.out.println(sb);