Tokens - Strings Java - java

I have the following assignment that I succeeded, however the code is very inefficient, I would appreciate if someone could show me a more efficient way, perhaps with substring. the assignment:
/**
* Separates a given string into tokens, which are the "words" that are
* separated by one or more occurrences of the given separator character.
* Returns the tokens as an array of String values.
*/
public static String[] tokenize (String str, char separator) {
// Removes all the occurrences of the separator at the beginning and end of str
String source = trim(str, separator);
String[] tokens = new String[charRunCount (source,separator)+1];
String tmp = ""; // a string in order to take a word, then run over this string
int j = 0;
int i = 0;
while (i < tokens.length) {
if ( source.charAt (j) != separator ) {
do {
tmp += source.charAt (j);
if ( j >= source.length () - 1 ) {
break;
}
else { // so that we math the source length
j++;
}
} while (source.charAt (j) != separator);
}
if ( source.charAt (j) == separator ) {
j++;
while (source.charAt (j) == separator) {
j++;
}
}
tokens[i] = tmp;// taking the token into place
tmp = ""; //resetting the token so we can begin anew
i++;
}
return tokens;
}
the cahrRunCount function:
public static int charRunCount(String str, char c){
char last = 0;
int counter = 0;
for (int i = 0; i < str.length(); i++) {
// whenever a run starts.
if (last != c && str.charAt(i) == c) {
counter++;
}
last = str.charAt(i);
}
return counter;
}
I cannot use import or regex, thank you!

Use String.split method
String[] tokens = str.split(separator)
for(String token:tokens){
//your code goes here
}
Docs here
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split(java.lang.String)

If you want, you can use the split method of the String class (just like #Amidala Siva Kumar suggested), like this:
public static String[] tokenize (String str, char separator) {
String[] tokens = str.split(separator);
return tokens;
}
Or, if you want to do it using your own split, you may do it like this (an improvement to your code).
public static String[] tokenize (String str, char separator) {
String sep = ""+separator;
int max_size = str.length() - str.replace(sep, "").length() +1 ; // Calculate max array size
String[] temp = new String[max_size];
int start = 0, index = 0, exact_size = 0;
int pos = str.indexOf(separator);
while (pos>=start) {
if (pos>start){
temp[index++] = str.substring(start,pos).trim();
exact_size++;
}
start = pos + 1;
pos = str.indexOf(separator,start);
}
String[] tokens = new String[exact_size];
System.arraycopy(temp, 0, tokens, 0, exact_size);
return tokens;
}
Hope you find it useful.

Related

Java Programming: Replace all but first and last letters of each word with "_"

The purpose of this method is replace all but the first and last letters of each word with "_". I'm a complete novice when it comes to coding, so I'm certain my code is fairly incorrect. I think where my code starts functioning improperly is with the while loop.
EDIT: How do I make this method without using arrays or extra methods, like the split method?
public static String blankWords(String s1) {
StringBuilder sb = new StringBuilder();
if(s1.length() > 2) {
sb.append(s1.charAt(0));
for(int x = 1; x < s1.length() - 1; x = x + 1) {
char y = ' ';
while(y != s1.charAt(x)) {
sb.append("_");
x = x + 1;
}
}
sb.append(s1.charAt(s1.length() - 1));
return sb.toString();
}
return s1;
}
What my code is outputting:
HW2.blankWords("This is a Test.")
java.lang.StringIndexOutOfBoundsException: String index out of range: 15
at java.lang.String.charAt(Unknown Source)
at HW2.blankWords(HW2.java:73)
What my code should output:
HW2.blankWords("This is a Test.")
"T__s is a T__t."
Here is a pretty simple solution:
class Scratch {
public static void main(String[] args) {
System.out.println(blankWords("My name is sam orozco"));
}
public static String delim = "_";
public static String blankWords(String s1) {
// this split arg on one or more space
String[] words = s1.split("\\s+");
StringBuilder response = new StringBuilder();
for (String val : words) {
val = convertWord(val);
response.append(val).append(" ");
}
return response.toString().trim();
}
public static String convertWord(String val) {
int len = val.length();
StringBuilder bldr = new StringBuilder();
int index = 0;
for (char ch : val.toCharArray()) {
if (index == 0 || index == len - 1) {
bldr.append(ch);
} else {
bldr.append(delim);
}
index++;
}
return bldr.toString();
}
}
You can do this using a StringTokenizer that will extract words based on a list of delimiters. Since you want to keep those delimiters in the output, you'll instruct the tokenizer to return them as tokens:
String blankWords(String s) {
// build a tokenizer for your string, listing all special chars as delimiters. The last argument says that delimiters are going to be returned as tokens themselves (so we can include them in the output string)
StringTokenizer tokenizer = new StringTokenizer(s, " .,;:?!()[]{}", true);
// a helper class to build the output string; think of it as just a more efficient concat utility
StringBuilder sb = new StringBuilder();
while (tokenizer.hasMoreTokens()) {
String blankWord = blank(tokenizer.nextToken());
sb.append(blankWord);
}
return sb.toString();
}
/**
* Replaces all but the first and last characters in a string with '_'
*/
private String blank(String word) {
// strings of up to two chars will be returned as such
// delimiters will always fall into this category, as they are always single characters
if (word.length() <= 2) {
return word;
}
// no need to iterate through all chars, we'll just get the array
final char[] chars = word.toCharArray();
// fill the array of chars with '_', starting with position 1 (the second char) up to the last char (exclusive, i.e. last-but-one)
Arrays.fill(chars, 1, chars.length - 1, '_');
// build the resulting word based on the modified array of chars
return new String(chars);
}
Here is the contents of a test that validates this implementation, using TestNG:
#Test(dataProvider = "texts")
public void testBlankWords(String input, String expectedOutput) {
assertEquals(blankWords(input), expectedOutput);
}
#DataProvider
public Object[][] texts() {
return new Object[][] {
{"This is a test.", "T__s is a t__t."},
{"This one, again, is (yet another) test!", "T__s o_e, a___n, is (y_t a_____r) t__t!"}
};
}
The main drawback of this implementation is that StringTokenizer requires you to list all the delimiters by hand. With a more advanced implementation, you can consider a delimiter any character that returns false for Character.isAlphabetic(c) or however you decide to define your non-word chars.
P.S.
This could be a "more advanced implementation", as I mentioned above:
static String blankWords(String text) {
final char[] textChars = text.toCharArray();
int wordStart = -1; // keep track of the current word start position, -1 means no current word
for (int i = 0; i < textChars.length; i++) {
if (!Character.isAlphabetic(textChars[i])) {
if (wordStart >= 0) {
for (int j = wordStart + 1; j < i - 1; j++) {
textChars[j] = '_';
}
}
wordStart = -1; // reset the current word to none
} else if (wordStart == -1) {
wordStart = i; // alphabetic characters start a new word, when there's none started already
} else if (i == textChars.length - 1) { // if the last character is aplhabetic
for (int j = wordStart + 1; j < i; j++) {
textChars[j] = '_';
}
}
}
return new String(textChars);
}
No while loop necessary!
Look ahead by 1 character to see if it's a space, or if the current character is a space, in that case you append it. Otherwise you make sure to add the next character (skipNext false).
Always add the last character
public static String blankWords(String s1) {
StringBuilder sb = new StringBuilder();
if(s1.length() > 2) {
Boolean skipNext = false;
for(int x = 0; x < s1.length() - 1; x = x + 1) {
if(s1.charAt(x) == ' ' || s1.charAt(x + 1) == ' ') {
sb.append(s1.charAt(x));
skipNext = false;
}
else {
if(skipNext) {
sb.append('_');
}
else {
sb.append(s1.charAt(x));
skipNext = true;
}
}
}
sb.append(s1.charAt(s1.length() - 1));
return sb.toString();
}
return s1;
}
For the more advanced programmer, use regular expression.
public static String blankWords(String s1) {
return s1.replaceAll("\\B\\w\\B", "_");
}
This correctly keeps the final t, i.e. blankWords("This is a Test.") returns "T__s is a T__t.".

implement basic string compression

I am working on question 1.5 from the book Cracking The Coding interview. The problem is to take a string "aabcccccaaa" and turn it into a2b1c5a3.
If the compressed string is not smaller than the original string, then return the original string.
My code is below. I used an ArrayList because I would not know how long the compressed string would be.
My output is [a, 2, b, 1, c, 5], aabc, []. When the program gets to the end of string, it doesn't have a character to compare the last character too.
import java.util.*;
import java.io.*;
public class stringCompression {
public static void main(String[] args) {
String a = "aabcccccaaa";
String b = "aabc";
String v = "aaaa";
check(a);
System.out.println("");
check(b);
System.out.println("");
check(v);
}
public static void check(String g){
ArrayList<Character> c = new ArrayList<Character>();
int count = 1;
int i = 0;
int h = g.length();
for(int j = i + 1; j < g.length(); j++)
{
if(g.charAt(i) == g.charAt(j)){
count++;
}
else {
c.add(g.charAt(i));
c.add((char)( '0' + count));
i = j;
count = 1;
}
}
if(c.size() == g.length()){
System.out.print(g);
}
else{
System.out.print(c);
}
}
}
In the last loop you're not adding the result to the array. When j = g.length() still needs to add the current char and count to the array. So you could check the next value of j before increment it:
for(int j = i + 1; j < g.length(); j++)
{
if(g.charAt(i) == g.charAt(j)){
count++;
}
else {
c.add(g.charAt(i));
c.add((char)( '0' + count));
i = j;
count = 1;
}
if((j + 1) = g.length()){
c.add(g.charAt(i));
c.add((char)( '0' + count));
}
}
I would use a StringBuilder rather than an ArrayList to build your compressed String. When you start compressing, the first character should already be added to the result. The count of the character will be added once you've encountered a different character. When you've reached the end of the String you should just be appending the remaining count to the result for the last letter.
public static void main(String[] args) throws Exception {
String[] data = new String[] {
"aabcccccaaa",
"aabc",
"aaaa"
};
for (String d : data) {
System.out.println(compress(d));
}
}
public static String compress(String str) {
StringBuilder compressed = new StringBuilder();
// Add first character to compressed result
char currentChar = str.charAt(0);
compressed.append(currentChar);
// Always have a count of 1
int count = 1;
for (int i = 1; i < str.length(); i++) {
char nextChar = str.charAt(i);
if (currentChar == nextChar) {
count++;
} else {
// Append the count of the current character
compressed.append(count);
// Set the current character and count
currentChar = nextChar;
count = 1;
// Append the new current character
compressed.append(currentChar);
}
}
// Append the count of the last character
compressed.append(count);
// If the compressed string is not smaller than the original string, then return the original string
return (compressed.length() < str.length() ? compressed.toString() : str);
}
Results:
a2b1c5a3
aabc
a4
You have two errors:
one that Typo just mentioned, because your last character was not added;
and another one, if the original string is shorter like "abc" with only three chars: "a1b1c1" has six chars (the task is "If the compressed string is not smaller than the original string, then return the original string.")
You have to change your if statement, ask for >= instead of ==
if(c.size() >= g.length()){
System.out.print(g);
} else {
System.out.print(c);
}
Use StringBuilder and then iterate on the input string.
private static string CompressString(string inputString)
{
var count = 1;
var compressedSb = new StringBuilder();
for (var i = 0; i < inputString.Length; i++)
{
// Check if we are at the end
if(i == inputString.Length - 1)
{
compressedSb.Append(inputString[i] + count.ToString());
break;
}
if (inputString[i] == inputString[i + 1])
count++;
else
{
compressedSb.Append(inputString[i] + count.ToString());
count = 1;
}
}
var compressedString = compressedSb.ToString();
return compressedString.Length > inputString.Length ? inputString : compressedString;
}

Reverse every 2nd word of a sentence

I am trying to reverse every 2nd words of every single sentence like
If a given string is :
My name is xyz
The desired output should be :
My eman is zyx
My current output is:
Ym eman s1 zyx
I am not able to achieve my desired output.Don't know what I am doing wrong here
Here is my code
char[] sentence = " Hi my name is person!".toCharArray();
System.out.println(ReverseSentence(sentence));
}
private static char[] ReverseSentence(char[] sentence)
{
//Given: "Hi my name is person!"
//produce: "iH ym eman si !nosrep"
if(sentence == null) return null;
if(sentence.length == 1) return sentence;
int startPosition=0;
int counter = 0;
int sentenceLength = sentence.length-1;
//Solution handles any amount of spaces before, between words etc...
while(counter <= sentenceLength)
{
if(sentence[counter] == ' ' && startPosition != -1 || sentenceLength == counter) //Have passed over a word so upon encountering a space or end of string reverse word
{
//swap from startPos to counter - 1
//set start position to -1 and increment counter
int begin = startPosition;
int end;
if(sentenceLength == counter)
{
end = counter;
}
else
end = counter -1;
char tmp;
//Reverse characters
while(end >= begin){
tmp = sentence[begin];
sentence[begin] = sentence[end];
sentence[end] = tmp;
end--; begin++;
}
startPosition = -1; //flag used to indicate we have no encountered a character of a string
}
else if(sentence[counter] !=' ' && startPosition == -1) //first time you encounter a letter in a word set the start position
{
startPosition = counter;
}
counter++;
}
return sentence;
}
If you want to reverse the alternate word you can try something like splitting the whole String into words delimited by whitespaces and apply StringBuilder reverse() on every second word like :-
String s = "My name is xyz";
String[] wordsArr = s.split(" "); // broke string into array delimited by " " whitespace
StringBuilder sb = new StringBuilder();
for(int i = 0 ; i< wordsArr.length; i++){ // loop over array length
if(i%2 == 0) // if 1st word, 3rd word, 5th word..and so on words
sb.append(wordsArr[i]); // add the word as it is
else sb.append(new StringBuilder(wordsArr[i]).reverse()); // else use StringBuilder revrese() to reverse it
sb.append(" ");// add a whitespace in between words
}
System.out.println(sb.toString().trim()); //remove extra whitespace from the end and convert StringBuilder to String
Output :- My eman is zyx
You can solve your problem vary easy way! Just use a flag variable which will indicate the even or odd position, more precisely whether any word will gonna be reversed or not!
Look at the following modification I made in your code, just added three extra line:
private static boolean flag = true;// added a variable flag to check if we reverse the word or not.
private static char[] ReverseSentence(char[] sentence)
{
//Given: "Hi my name is person!"
//produce: "iH ym eman si !nosrep"
if(sentence == null) return null;
if(sentence.length == 1) return sentence;
int startPosition=0;
int counter = 0;
int sentenceLength = sentence.length-1;
//Solution handles any amount of spaces before, between words etc...
while(counter <= sentenceLength)
{
if(sentence[counter] == ' ' && startPosition != -1 || sentenceLength == counter) //Have passed over a word so upon encountering a space or end of string reverse word
{
flag = !flag; // first time (odd position) we are not going to reverse!
//swap from startPos to counter - 1
//set start position to -1 and increment counter
int begin = startPosition;
int end;
if(sentenceLength == counter)
{
end = counter;
}
else
end = counter -1;
char tmp;
//Reverse characters
while(end >= begin & flag){ //lets see whether we are going to reverse or not
tmp = sentence[begin];
sentence[begin] = sentence[end];
sentence[end] = tmp;
end--; begin++;
}
startPosition = -1; //flag used to indicate we have no encountered a character of a string
}
else if(sentence[counter] !=' ' && startPosition == -1) //first time you encounter a letter in a word set the start position
{
startPosition = counter;
}
counter++;
}
return sentence;
}
Input
My name is xyz
Output:
My eman is zyx
The following code does this "special reverse" which reverses any other word in the sentence:
public static void main(String[] args) {
String sentence = "My name is xyz";
System.out.println(specialReverse(sentence)); // My eman is zyx
}
private static String specialReverse(String sentence) {
String result = "";
String[] words = sentence.split(" ");
// we'll reverse only every second word according to even/odd index
for (int i = 0; i < words.length; i++) {
if (i % 2 == 1) {
result += " " + reverse(words[i]);
} else {
result += " " + words[i];
}
}
return result;
}
// easiest way to reverse a string in Java in a "one-liner"
private static String reverse(String word) {
return new StringBuilder(word).reverse().toString();
}
Just for completeness here's Java-8 solution:
public static String reverseSentence(String input) {
String[] words = input.split(" ");
return IntStream.range(0, words.length)
.mapToObj( i -> i % 2 == 0 ? words[i] :
new StringBuilder(words[i]).reverse().toString())
.collect(Collectors.joining(" "));
}
reverseSentence("My name is xyz"); // -> My eman is zyx
package com.eg.str;
// Without using StringBuilder
// INPUT: "Java is very cool prog lang"
// OUTPUT: Java si very looc prog gnal
public class StrRev {
public void reverse(String str) {
String[] tokens = str.split(" ");
String result = "";
String k = "";
for(int i=0; i<tokens.length; i++) {
if(i%2 == 0)
System.out.print(" " + tokens[i] + " ");
else
result = tokens[i];
for (int j = result.length()-1; j >= 0; j--) {
k = "" + result.charAt(j);
System.out.print(k);
}
result = "";
}
}
public static void main(String[] args) {
StrRev obj = new StrRev();
obj.reverse("Java is very cool prog lang");
}
}
//reverse second word of sentence in java
public class ReverseSecondWord {
public static void main(String[] args) {
String s="hello how are you?";
String str[]=s.split(" ");
String rev="";
for(int i=0;i<str[1].length();i++)
{
char ch=str[1].charAt(i);
rev=ch+rev;
}
str[1]=rev;
for(int i=0;i<str.length;i++)
{
System.out.print(str[i]+" ");
}
}
}

How can I split a string into words in Java without using String.split()?

My teacher specifically requested that we split a sentence into words without using String.split(). I've done it using a Vector (which we haven't learned), a while-loop, and substrings. What are other ways of accomplishing this? (preferably without using Vectors/ArrayLists).
I believe that your teacher is asking you to process the string yourself (without using any other libraries to do it for you). Check to see if this is the case - if you can use them, there are things such as StringTokenizer, Pattern, and Scanner to facilitate string processing.
Otherwise...
You will need a list of word separators (such as space, tab, period, etc...) and then walk the array, building a string a character at a time until you hit the word separator. After finding a complete word (you have encountered a word separator character), save it the variable out into your structure (or whatever is required), reset the variable you are building the word in and continue.
Parsing the string character by character, copying each character into a new String, and stopping when you reach a white space character. Then start a new string and continue until you reach the end of the original string.
You can use java.util.StringTokenizer to split a text using desired delimiter. Default delimiter is SPACE/TAB/NEW_LINE.
String myTextToBeSplit = "This is the text to be split into words.";
StringTokenizer tokenizer = new StringTokenizer( myTextToBeSplit );
while ( tokinizer.hasMoreTokens()) {
String word = tokinizer.nextToken();
System.out.println( word ); // word you are looking in
}
As an alternate you can also use java.util.Scanner
Scanner s = new Scanner(myTextToBeSplit).useDelimiter("\\s");
while( s.hasNext() ) {
System.out.println(s.next());
}
s.close();
You can use java.util.Scanner.
import java.util.Arrays;
public class ReverseTheWords {
public static void main(String[] args) {
String s = "hello java how do you do";
System.out.println(Arrays.toString(ReverseTheWords.split(s)));
}
public static String[] split(String s) {
int count = 0;
char[] c = s.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == ' ') {
count++;
}
}
String temp = "";
int k = 0;
String[] rev = new String[count + 1];
for (int i = 0; i < c.length; i++) {
if (c[i] == ' ') {
rev[k++] = temp;
temp = "";
} else
temp = temp + c[i];
}
rev[k] = temp;
return rev;
}
}
YOu can use StringTokenizer
http://www.java-samples.com/showtutorial.php?tutorialid=236
Or use a Pattern (also known as a regular expression) to try to match the words.
Use a Scanner with ctor (String)
regular expressions and match
StringTokenizer
iterating yourself char by char
recursive iteration
Without using a Vector/List (and without manually re-implementing their ability to re-size themselves for your function), you can take advantage of the simple observation that a string of length N cannot have more than (N+1)/2 words (in integer division). You can declare an array of strings of that size, populate it the same way you populated that Vector, and then copy the results to an array of the size of the number of words you found.
So:
String[] mySplit( String in ){
String[] bigArray = new String[ (in.length()+1)/2 ];
int numWords = 0;
// Populate bigArray with your while loop and keep
// track of the number of words
String[] result = new String[numWords];
// Copy results from bigArray to result
return result;
}
public class MySplit {
public static String[] mySplit(String text,String delemeter){
java.util.List<String> parts = new java.util.ArrayList<String>();
text+=delemeter;
for (int i = text.indexOf(delemeter), j=0; i != -1;) {
parts.add(text.substring(j,i));
j=i+delemeter.length();
i = text.indexOf(delemeter,j);
}
return parts.toArray(new String[0]);
}
public static void main(String[] args) {
String str="012ab567ab0123ab";
String delemeter="ab";
String result[]=mySplit(str,delemeter);
for(String s:result)
System.out.println(s);
}
}
public class sha1 {
public static void main(String[] args) {
String s = "hello java how do you do";
System.out.println(Arrays.toString(sha1.split(s)));
}
public static String[] split(String s) {
int count = 0;
char[] c = s.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == ' ') {
count++;
}
}
String temp = "";
int k = 0;
String[] rev = new String[count + 1];
for (int i = c.length-1; i >= 0; i--) {
if (c[i] == ' ') {
rev[k++] = temp;
temp = "";
} else
temp = temp + c[i];
}
rev[k] = temp;
return rev;
}
}
Simple touch.! Improve if you want to.
package com.asif.test;
public class SplitWithoutSplitMethod {
public static void main(String[] args) {
split('#',"asif#is#handsome");
}
static void split(char delimeter, String line){
String word = "";
String wordsArr[] = new String[3];
int k = 0;
for(int i = 0; i <line.length(); i++){
if(line.charAt(i) != delimeter){
word+= line.charAt(i);
}else{
wordsArr[k] = word;
word = "";
k++;
}
}
wordsArr[k] = word;
for(int j = 0; j <wordsArr.length; j++)
System.out.println(wordsArr[j]);
}
}
Please try this .
public static String[] mysplit(String mystring) {
String string=mystring+" "; //append " " bcz java string does not hava any ending character
int[] spacetracker=new int[string.length()];// to count no. of spaces in string
char[] array=new char[string.length()]; //store all non space character
String[] tokenArray=new String[string.length()];//to return token of words
int spaceIndex=0;
int parseIndex=0;
int arrayIndex=0;
int k=0;
while(parseIndex<string.length())
{
if(string.charAt(parseIndex)==' '||string.charAt(parseIndex)==' ')
{
spacetracker[spaceIndex]=parseIndex;
spaceIndex++;
parseIndex++;
}else
{
array[arrayIndex]=string.charAt(parseIndex);
arrayIndex++;
parseIndex++;
}
}
for(int i=0;i<spacetracker.length;i++)
{
String token="";
for(int j=k;j<(spacetracker[i])-i;j++)
{
token=token+array[j];
k++;
}
tokenArray[i]=token;
//System.out.println(token);
token="";
}
return tokenArray;
}
Hope this helps
import java.util.*;
class StringSplit {
public static void main(String[] args)
{
String s="splitting a string without using split()";
ArrayList<Integer> al=new ArrayList<Integer>(); //Instead you can also use a String
ArrayList<String> splitResult=new ArrayList<String>();
for(int i=0;i<s.length();i++)
if(s.charAt(i)==' ')
al.add(i);
al.add(0, 0);
al.add(al.size(),s.length());
String[] words=new String[al.size()];
for(int j=0;j<=words.length-2;j++)
splitResult.add(s.substring(al.get(j),al.get(j+1)).trim());
System.out.println(splitResult);
}
}
Time complexity: O(n)
You can use java Pattern to do it in easy way.
package com.company;
import java.util.regex.Pattern;
public class umeshtest {
public static void main(String a[]) {
String ss = "I'm Testing and testing the new feature";
Pattern.compile(" ").splitAsStream(ss).forEach(s -> System.out.println(s));
}
}
You can also use String.substring or charAt[].

Write a method to replace all spaces in a string with '%20'

I have a question about a programming problem from the book Cracking The Code Interview by Gayl Laakmann McDowell, 5th Edition.
The problem states: Write a method to replace all spaces in a string with '%20'. Assume string has sufficient space at end of string to hold additional characters, and that you're given a true length of a string. I used the books code, implementing the solution in Java using a character array (given the fact that Java Strings are immutable):
public class Test {
public void replaceSpaces(char[] str, int length) {
int spaceCount = 0, newLength = 0, i = 0;
for(i = 0; i < length; i++) {
if (str[i] == ' ')
spaceCount++;
}
newLength = length + (spaceCount * 2);
str[newLength] = '\0';
for(i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
str[newLength - 1] = '0';
str[newLength - 2] = '2';
str[newLength - 3] = '%';
newLength = newLength - 3;
}
else {
str[newLength - 1] = str[i];
newLength = newLength - 1;
}
}
System.out.println(str);
}
public static void main(String[] args) {
Test tst = new Test();
char[] ch = {'t', 'h', 'e', ' ', 'd', 'o', 'g', ' ', ' ', ' ', ' ', ' ', ' '};
int length = 6;
tst.replaceSpaces(ch, length);
}
}
The output I am getting from the replaceSpaces() call is: the%20do which is cutting of the last character of the original array. I have been scratching my head over this, can anyone explain to me why the algorithm is doing this?
public String replace(String str) {
String[] words = str.split(" ");
StringBuilder sentence = new StringBuilder(words[0]);
for (int i = 1; i < words.length; ++i) {
sentence.append("%20");
sentence.append(words[i]);
}
return sentence.toString();
}
You are passing the length as 6, which is causing this. Pass length as 7 including space.
Other wise
for(i = length - 1; i >= 0; i--) {
will not consider last char.
With these two changes I got the output: the%20dog
1) Change space count to 2 [since length already includes 1 of the 3 characters you need for %20]
newLength = length + (spaceCount * 2);
2) Loop should start on length
for(i = length; i >= 0; i--) {
Here is my solution. I check for the ascii code 32 then put a %20 instead of it.Time complexity of this solution is O(N)
public String replace(String s) {
char arr[] = s.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 32)
sb.append("%20");
else
sb.append(arr[i]);
}
return sb.toString();
}
This is my code for this question. Seems like working for me. If you're interested, please have a look. It's written in JAVA
public class ReplaceSpaceInString {
private static char[] replaceSpaceInString(char[] str, int length) {
int spaceCounter = 0;
//First lets calculate number of spaces
for (int i = 0; i < length; i++) {
if (str[i] == ' ')
spaceCounter++;
}
//calculate new size
int newLength = length + 2*spaceCounter;
char[] newArray = new char[newLength+1];
newArray[newLength] = '\0';
int newArrayPosition = 0;
for (int i = 0; i < length; i++) {
if (str[i] == ' ') {
newArray[newArrayPosition] = '%';
newArray[newArrayPosition+1] = '2';
newArray[newArrayPosition+2] = '0';
newArrayPosition = newArrayPosition + 3;
}
else {
newArray[newArrayPosition] = str[i];
newArrayPosition++;
}
}
return newArray;
}
public static void main(String[] args) {
char[] array = {'a','b','c','d',' ','e','f','g',' ','h',' ','j'};
System.out.println(replaceSpaceInString(array, array.length));
}
}
You can also use substring method and the ascii for space (32).
public String replaceSpaceInString(String s){
int i;
for (i=0;i<s.length();i++){
System.out.println("i is "+i);
if (s.charAt(i)==(int)32){
s=s.substring(0, i)+"%20"+s.substring(i+1, s.length());
i=i+2;
}
}
return s;
}
To test:
System.out.println(cc.replaceSpaceInString("mon day "));
Output:
mon%20day%20
You could just do this.
No need to calculate the length or whatever.
Strings are immutable anyways.
import java.util.*;
public class ReplaceString {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String str=in.nextLine();
String n="";
for(int i=0;i<str.length();i++)
{
if(str.charAt(i)==' ')
n=n+"%20";
else
n=n+str.charAt(i);
}
str=n;
System.out.println(str);
}
}
void Rep_Str(char *str)
{
int j=0,count=0;
int stlen = strlen(str);
for (j = 0; j < stlen; j++)
{
if (str[j]==' ')
{
count++;
}
}
int newlength = stlen+(count*2);
str[newlength--]='\0';
for (j = stlen-1; j >=0 ; j--)
{
if (str[j]==' ')
{
str[newlength--]='0';
str[newlength--]='2';
str[newlength--]='%';
}
else
{
str[newlength--]=str[j];
}
}
}
This code works :)
We can use a regular expression to solve this problem. For example:
public String replaceStringWithSpace(String str){
return str.replaceAll("[\\s]", "%20");
}
This works correctly. However, using a StringBuffer object increases space complexity.
Scanner scn = new Scanner(System.in);
String str = scn.nextLine();
StringBuffer sb = new StringBuffer(str.trim());
for(int i = 0;i<sb.length();i++){
if(32 == (int)sb.charAt(i)){
sb.replace(i,i+1, "%20");
}
}
public static String replaceAllSpaces(String s) {
char[] c = s.toCharArray();
int spaceCount = 0;
int trueLen = s.length();
int index = 0;
for (int i = 0; i < trueLen; i++) {
if (c[i] == ' ') {
spaceCount++;
}
}
index = trueLen + spaceCount * 2;
char[] n = new char[index];
for (int i = trueLen - 1; i >= 0; i--) {
if (c[i] == ' ') {
n[index - 1] = '0';
n[index - 2] = '2';
n[index - 3] = '%';
index = index - 3;
} else {
n[index - 1] = c[i];
index--;
}
}
String x = new String(n);
return x;
}
Another way of doing this.
I am assuming the trailing spaces don't need to be converted to %20 and that the trailing spaces provide enough room for %20s to be stuffed in between
public class Main {
public static void main(String[] args) {
String str = "a sd fghj ";
System.out.println(replacement(str));//a%20sd%20fghj
}
private static String replacement(String str) {
char[] chars = str.toCharArray();
int posOfLastChar = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] != ' ') {
posOfLastChar = i;
}
}
int newCharPosition = chars.length - 1;
//Start moving the characters to th end of the array. Replace spaces by %20
for (int i = posOfLastChar; i >= 0; i--) {
if (chars[i] == ' ') {
chars[newCharPosition] = '0';
chars[--newCharPosition] = '2';
chars[--newCharPosition] = '%';
} else {
chars[newCharPosition] = chars[i];
}
newCharPosition--;
}
return String.valueOf(chars);
}
}
public class ReplaceChar{
public static void main(String []args){
String s = "ab c de ";
System.out.println(replaceChar(s));
}
public static String replaceChar(String s){
boolean found = false;
StringBuilder res = new StringBuilder(50);
String str = rev(s);
for(int i = 0; i <str.length(); i++){
if (str.charAt(i) != ' ') { found = true; }
if (str.charAt(i) == ' '&& found == true) { res.append("%02"); }
else{ res.append(str.charAt(i)); }
}
return rev(res.toString());
}
// Function to reverse a string
public static String rev(String s){
StringBuilder result = new StringBuilder(50);
for(int i = s.length()-1; i>=0; i-- ){
result.append(s.charAt(i));
}
return result.toString();
}}
A simple approach:
Reverse the given string and check where the first character appears.
Using string builder to append "02%" for spaces - since the string is reversed.
Finally reverse the string once again.
Note: We reverse the string so as to prevent an addition of "%20" to the trailing spaces.
Hope that helps!
The question in the book mentions that the replacement should be in place so it is not possible to assign extra arrays, it should use constant space. You should also take into account many edge cases, this is my solution:
public class ReplaceSpaces {
public static void main(String[] args) {
if ( args.length == 0 ) {
throw new IllegalArgumentException("No string");
}
String s = args[0];
char[] characters = s.toCharArray();
replaceSpaces(characters);
System.out.println(characters);
}
static void replaceSpaces(char[] s) {
int i = s.length-1;
//Skipping all spaces in the end until setting `i` to non-space character
while( i >= 0 && s[i] == ' ' ) { i--; }
/* Used later to check there is enough extra space in the end */
int extraSpaceLength = s.length - i - 1;
/*
Used when moving the words right,
instead of finding the first non-space character again
*/
int lastNonSpaceCharacter = i;
/*
Hold the number of spaces in the actual string boundaries
*/
int numSpaces = 0;
/*
Counting num spaces beside the extra spaces
*/
while( i >= 0 ) {
if ( s[i] == ' ' ) { numSpaces++; }
i--;
}
if ( numSpaces == 0 ) {
return;
}
/*
Throw exception if there is not enough space
*/
if ( extraSpaceLength < numSpaces*2 ) {
throw new IllegalArgumentException("Not enough extra space");
}
/*
Now we need to move each word right in order to have space for the
ascii representation
*/
int wordEnd = lastNonSpaceCharacter;
int wordsCounter = 0;
int j = wordEnd - 1;
while( j >= 0 ) {
if ( s[j] == ' ' ){
moveWordRight(s, j+1, wordEnd, (numSpaces-wordsCounter)*2);
wordsCounter++;
wordEnd = j;
}
j--;
}
replaceSpacesWithAscii(s, lastNonSpaceCharacter + numSpaces * 2);
}
/*
Replaces each 3 sequential spaces with %20
char[] s - original character array
int maxIndex - used to tell the method what is the last index it should
try to replace, after that is is all extra spaces not required
*/
static void replaceSpacesWithAscii(char[] s, int maxIndex) {
int i = 0;
while ( i <= maxIndex ) {
if ( s[i] == ' ' ) {
s[i] = '%';
s[i+1] = '2';
s[i+2] = '0';
i+=2;
}
i++;
}
}
/*
Move each word in the characters array by x moves
char[] s - original character array
int startIndex - word first character index
int endIndex - word last character index
int moves - number of moves to the right
*/
static void moveWordRight(char[] s, int startIndex, int endIndex, int moves) {
for(int i=endIndex; i>=startIndex; i--) {
s[i+moves] = s[i];
s[i] = ' ';
}
}
}
Any reason not to use 'replace' method?
public String replaceSpaces(String s){
return s.replace(" ", "%20");}
Hm... I am wondering about this problem as well. Considering what I have seen in here. The book solution does not fit Java because it uses in-place
char []
modification and solutions in here that use char [] or return void don't fit as well because Java does not use pointers.
So I was thinking, the obvious solution would be
private static String encodeSpace(String string) {
return string.replcaceAll(" ", "%20");
}
but this is probably not what your interviewer would like to see :)
// make a function that actually does something
private static String encodeSpace(String string) {
//create a new String
String result = new String();
// replacement
final String encodeSpace = "%20";
for(char c : string.toCharArray()) {
if(c == ' ') result+=encodeString;
else result+=c;
}
return result;
}
this looks fine I thought, and you only need one pass through the string, so the complexity should be O(n), right? Wrong! The problem is in
result += c;
which is the same as
result = result + c;
which actually copies a string and creates a copy of it. In java strings are represented as
private final char value[];
which makes them immutable (for more info I would check java.lang.String and how it works). This fact will bump up the complexity of this algorithm to O(N^2) and a sneaky recruiter can use this fact to fail you :P Thus, I came in with a new low-level solution which you will never use in practice, but which is good in theory :)
private static String encodeSpace(String string) {
final char [] original = string != null? string.toCharArray() : new char[0];
// ASCII encoding
final char mod = 37, two = 50, zero = 48, space = 32;
int spaces = 0, index = 0;
// count spaces
for(char c : original) if(c == space) ++spaces;
// if no spaces - we are done
if(spaces == 0) return string;
// make a new char array (each space now takes +2 spots)
char [] result = new char[string.length()+(2*spaces)];
for(char c : original) {
if(c == space) {
result[index] = mod;
result[++index] = two;
result[++index] = zero;
}
else result[index] = c;
++index;
}
return new String(result);
}
But I wonder what is wrong with following code:
private static String urlify(String originalString) {
String newString = "";
if (originalString.contains(" ")) {
newString = originalString.replace(" ", "%20");
}
return newString;
}
Question : Urlify the spaces with %20
Solution 1 :
public class Solution9 {
public static void main(String[] args) {
String a = "Gini Gina Protijayi";
System.out.println( urlencode(a));
}//main
public static String urlencode(String str) {
str = str.trim();
System.out.println("trim =>" + str);
if (!str.contains(" ")) {
return str;
}
char[] ca = str.toCharArray();
int spaces = 0;
for (char c : ca) {
if (c == ' ') {
spaces++;
}
}
char[] newca = new char[ca.length + 2 * spaces];
// a pointer x has been added
for (int i = 0, x = 0; i < ca.length; i++) {
char c = ca[i];
if (c == ' ') {
newca[x] = '%';
newca[x + 1] = '2';
newca[x + 2] = '0';
x += 3;
} else {
newca[x] = c;
x++;
}
}
return new String(newca);
}
}//urlify
My solution using StringBuilder with time complexity O(n)
public static String url(String string, int length) {
char[] arrays = string.toCharArray();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
if (arrays[i] == ' ') {
builder.append("%20");
} else {
builder.append(arrays[i]);
}
}
return builder.toString();
}
Test case :
#Test
public void testUrl() {
assertEquals("Mr%20John%20Smith", URLify.url("Mr John Smith ", 13));
}
Can you use StringBuilder?
public String replaceSpace(String s)
{
StringBuilder answer = new StringBuilder();
for(int i = 0; i<s.length(); i++)
{
if(s.CharAt(i) == ' ')
{
answer.append("%20");
}
else
{
answer.append(s.CharAt(i));
}
}
return answer.toString();
}
I am also looking at that question in the book. I believe we can just use String.trim() and String.replaceAll(" ", "%20) here
I updated the solution here. http://rextester.com/CWAPCV11970
If we are creating new array and not in-place trasition, then why do we need to walk backwards?
I modified the real solution slightly to walk forward to create target Url-encoded-string.
Time complexity:
O(n) - Walking original string
O(1) - Creating target string incrementally
where 'n' is number of chars in original string
Space complexity:
O(n + m) - Duplicate space to store escaped spaces and string.
where 'n' is number of chars in original string and 'm' is length of escaped spaces
public static string ReplaceAll(string originalString, char findWhat, string replaceWith)
{
var newString = string.Empty;
foreach(var character in originalString)
newString += findWhat == character? replaceWith : character + string.Empty;
return newString;
}
class Program
{
static void Main(string[] args)
{
string name = "Stack Over Flow ";
StringBuilder stringBuilder = new StringBuilder();
char[] array = name.ToCharArray(); ;
for(int i = 0; i < name.Length; i++)
{
if (array[i] == ' ')
{
stringBuilder.Append("%20");
}
else
stringBuilder.Append(array[i]);
}
Console.WriteLine(stringBuilder);
Console.ReadLine();
}
}
public class Sol {
public static void main(String[] args) {
String[] str = "Write a method to replace all spaces in a string with".split(" ");
StringBuffer sb = new StringBuffer();
int count = 0;
for(String s : str){
sb.append(s);
if(str.length-1 != count)
sb.append("%20");
++count;
}
System.out.println(sb.toString());
}
}
public class Test {
public static void replace(String str) {
String[] words = str.split(" ");
StringBuilder sentence = new StringBuilder(words[0]);
for (int i = 1; i < words.length; i++) {
sentence.append("%20");
sentence.append(words[i]);
}
sentence.append("%20");
System.out.println(sentence.toString());
}
public static void main(String[] args) {
replace("Hello World "); **<- Hello<3spaces>World<1space>**
}
}
O/P:: Hello%20%20%20World%20
Remember that you only to want replace ' ' with '%20' when the latter is not a leading or trailing space. Several answers above do not account for this. For what it's worth, I get "index out of bounds error" when I run Laakmann's solution example.
Here's my own solution, which runs O(n) and is implemented in C#:
public static string URLreplace(string str, int n)
{
var len = str.Length;
if (len == n)
return str;
var sb = new StringBuilder();
var i = 0;
while (i < len)
{
char c = str[i];
if (c == ' ')
{
while (i < len && str[i] == ' ')
{
i++; //skip ahead
}
}
else
{
if (sb.Length > 0 && str[i - 1] == ' ')
sb.Append("%20" + c);
else
sb.Append(c);
i++;
}
}
return sb.ToString();
}
Test:
//Arrange
private string _str = " Mr John Smith ";
private string _result = "Mr%20John%20Smith";
private int _int = 13;
[TestMethod]
public void URLified()
{
//Act
var cleaned = URLify.URLreplace(_str, _int);
//Assert
Assert.IsTrue(cleaned == _result);
}
One line code
System.out.println(s.trim().replace(" ","%20"));
// while passing the input make sure you use the .toCharArray method becuase strings are immutable
public static void replaceSpaces(char[] str, int length) {
int spaceCount = 0, newLength = 0, i = 0;
for (i = 0; i < length; i++) {
if (str[i] == ' ')
spaceCount++;
}
newLength = length + (spaceCount * 2);
// str[newLength] = '\0';
for (i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
str[newLength - 1] = '0';
str[newLength - 2] = '2';
str[newLength - 3] = '%';
newLength = newLength - 3;
} else {
str[newLength - 1] = str[i];
newLength = newLength - 1;
}
}
System.out.println(str);
}
public static void main(String[] args) {
// Test tst = new Test();
char[] ch = "Mr John Smith ".toCharArray();
int length = 13;
replaceSpaces(ch, length);
}
`// Maximum length of string after modifications.
const int MAX = 1000;
// Replaces spaces with %20 in-place and returns
// new length of modified string. It returns -1
// if modified string cannot be stored in str[]
int replaceSpaces(char str[])
{
// count spaces and find current length
int space_count = 0, i;
for (i = 0; str[i]; i++)
if (str[i] == ' ')
space_count++;
// Remove trailing spaces
while (str[i-1] == ' ')
{
space_count--;
i--;
}
// Find new length.
int new_length = i + space_count * 2 + 1;
// New length must be smaller than length
// of string provided.
if (new_length > MAX)
return -1;
// Start filling character from end
int index = new_length - 1;
// Fill string termination.
str[index--] = '\0';
// Fill rest of the string from end
for (int j=i-1; j>=0; j--)
{
// inserts %20 in place of space
if (str[j] == ' ')
{
str[index] = '0';
str[index - 1] = '2';
str[index - 2] = '%';
index = index - 3;
}
else
{
str[index] = str[j];
index--;
}
}
return new_length;
}
// Driver code
int main()
{
char str[MAX] = "Mr John Smith ";
// Prints the replaced string
int new_length = replaceSpaces(str);
for (int i=0; i<new_length; i++)
printf("%c", str[i]);
return 0;
}`

Categories