Example (replacing 'text' with '...'):
Before:
text(text)text
After:
...(text)...
In this case it is easier to find what you want to keep, and replace the rest.
E.g. like this:
static String abbreviate(String input, String openTag, String closeTag) {
String regex = Pattern.quote(openTag) + ".*?" + Pattern.quote(closeTag);
StringBuilder buf = new StringBuilder();
int start = 0;
for (Matcher m = Pattern.compile(regex).matcher(input); m.find(); start = m.end()) {
if (start < m.start())
buf.append("...");
buf.append(m.group());
}
if (start < input.length())
buf.append("...");
return buf.toString();
}
Test
System.out.println(abbreviate("text(text)text(text)text", "(", ")"));
System.out.println(abbreviate("text$text$text$text$text$text", "$", "$"));
System.out.println(abbreviate("text(text)text", ")", "("));
Output
...(text)...(text)...
...$text$...$text$...
...
You need to iterate over the characters and only append those that are between the two specified characters. This can be done as follows:
private String splitStr(String str, char first, char second) {
StringBuilder sb = new StringBuilder();
if(str.isEmpty() || str.indexOf(first) < 0 || str.indexOf(second) < 0)
return sb.toString();
char[] chars = str.toCharArray();
boolean append = false;
for(char c : chars) {
if(c == first) {
sb.append(c);
append = true;
}else if(c == second) {
sb.append(c);
append = false;
}else if(append)
sb.append(c);
}
return sb.toString();
}
Some sample cases are:
"text(text)text(text)text(text)text" => "(text)(text)(text)"
"text(text)text" => "(text)"
String s = "text(text)text";
String newString = s.replace("text", "...");
System.out.println(newString); //returns ...(...)...
Note that "(text)" still contains "text", the braces around it will not stop it from being replaced.
You need to assign the result to a new String to use it. Strings are immutable
Related
Steps for Deciphering the message
remove 3 at end of the string
replace ASCII values at even places(number clusters) with corresponding characters value.
replace * with spacing " ".
reverse the string
swap case of string- lowercase to upper case and vice versa.
Sample input: ?85O89*69R65*87O104*33I1043
Require output: Hi! How are you?
This is the whole method that I have written.
public String deciphering(String ciphered) {
StringBuilder a = new StringBuilder(ciphered);
StringBuilder b = a.deleteCharAt(a.length()-1);
char[] ch = new char[b.length()];
StringBuilder c = new StringBuilder();
for (int i = 0; i < b.length(); i++) {
ch[i] = b.charAt(i);
}
for (int i = 0; i < ch.length; i++) {
if(!Character.isDigit(ch[i]))
{
c.append(ch[i]);
}else
{
String temp = new String();
while(Character.isDigit(ch[i]) &&(i<b.length())){
temp = temp + ch[i];
i++;
}
int number = Integer.parseInt(temp);
char p = (char)number;
c.append(p);
}
}
String d = c.toString();
String e = d.replace('*', ' ');
StringBuffer f = new StringBuffer(e);
StringBuffer g = f.reverse();
for (int i = 0; i < g.length(); i++) {
if (Character.isLowerCase(g.charAt(i))){
char x = Character.toUpperCase(g.charAt(i));
g.setCharAt(i, x);
} else if (Character.isUpperCase(g.charAt(i))) {
char x = Character.toLowerCase(g.charAt(i));
g.setCharAt(i, x);
}
}
return g.toString();
}
You are incrementing i twice past the last digit of a chunk - when you exit your inner loop i is indexing the first non-digit character, then when you reach the end of the for loop body, the for loop is incrementing i again.
It may be better to split the input string into parts with non-digit delimiters and keep the delimiters using the following regular expression (using look-ahead and look-behind as described here) after removing the last character:
str.substring(0, str.length() - 1).split("(?<=\\D)|(?=\\D)")
Then Stream API may be used to convert each string into a separate character and insert these characters into prepared StringBuilder to implement reverse order in the result:
public static String decipher(String str) {
StringBuilder sb = new StringBuilder(str.length());
Arrays.stream(
str.substring(0, str.length() - 1).split("(?<=\\D)|(?=\\D)")
)
.map(p -> p.matches("\\d+") ? (char) Integer.parseInt(p): p.charAt(0))
.map(c -> c == '*' ? ' '
: Character.isLowerCase(c) ? Character.toUpperCase(c)
: Character.isUpperCase(c) ? Character.toLowerCase(c)
: c
)
.forEach(c -> sb.insert(0, c));
return sb.toString();
}
Test:
System.out.println(decipher("?85O89*69R65*87O104*33I1043"));
Output:
Hi! How are you?
The input is a (good) example((eo)--)e). I have used an iterative way.
I tried with the following code:
public String scartaParentesi(String s)
{
ups = s.replaceAll("\\([^()]*\\)", "");
return ups;
}
The output of this code is a example(--)e).
The expected output is a examplee).
Based on description and comments, you can do:
String str = "a (good) example((eo)--)e";
StringBuilder stringBuilder = new StringBuilder();
int openedParenthesesCount = 0;
for (char c : str.toCharArray()) {
if (c == '(') {
openedParenthesesCount++;
} else if (c == ')') {
openedParenthesesCount--;
} else if (openedParenthesesCount == 0) {
stringBuilder.append(c);
}
}
System.out.println(stringBuilder);
Output:
a examplee
Assumption - number of '(' equals to number of ')'.
A more robust solution without any assumptions of the number of opening and closing braces:
String text = "a (good) example((eo)--)e)";
StringBuilder outText = new StringBuilder();
Deque<Character> stack = new ArrayDeque<Character>();
int i=0;
while (i<text.length()) {
if (text.charAt(i) == '(') {
stack.addFirst(text.charAt(i));
i++;
}
while (!stack.isEmpty()) {
if (text.charAt(i) != ')') {
stack.addFirst(text.charAt(i));
i++;
} else {
if (stack.removeFirst() == '(') {
i++;
}
}
}
outText.append(text.charAt(i));
i++;
}
Output:
before: a (good) example((eo)--)e)
after: a examplee)
You can also use your original String replaceAll method by putting it on a loop, replacing the same pattern on the last updated string. The break condition of the loop will be checking if 2 consecutive iterations output the same string, i.e. no pattern to replace:
String prev = text.replaceAll("\\([^()]*\\)", "");
while (!text.equals(prev)) {
prev = text;
text = text.replaceAll("\\([^()]*\\)", "");
}
System.out.println("after2: " + text);
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.".
I have a question about a programming problem from the book Cracking The Code Interview by Gayl Laakmann McDowell, 5th Edition.
I'm not sure what is wrong with my answer? It varies a lot from the answer given in the book.
public String replace(String str){
String[] words = str.split(" ");
StringBuffer sentence = new StringBuffer();
for(String w: words){
sentence.append("%20");
sentence.append(w);
}
return sentence.toString();
}
Question in the book says:
Note: if implementing in Java, please use a character array so that
you can perform this operation in place.
It also says that the char array that you get as input is long enough to hold the modified string.
By using split and StringBuffer you use additional O(n) space. That's why your answer varies a lot and is incorrect (apart from adding additional "%20").
In this loop, the program adds %20 before each word:
for(String w: words){
sentence.append("%20");
sentence.append(w);
}
That will produce incorrect results, for example for a b it will give %20a%20b.
There's a much simpler solution:
public String replace(String str) {
return str.replaceAll(" ", "%20");
}
Or, if you really don't want to use .replaceAll, then write like 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 can also do the following, which replaces any space
String s = "Hello this is a string!";
System.out.println(replaceSpace(s, "%20"));
public static String replaceSpace(String s, String replacement) {
String ret = s.replaceAll(" *", replacement);
return ret;
}
Gives
Hello%20this%20is%20a%20string!
One of the simplest way:
public void replaceAll( String str )
{
String temp = str.trim();
char[] arr = temp.toCharArray();
StringBuffer sb = new StringBuffer();
for( int i = 0; i < arr.length; i++ )
{
if( arr[i] == ' ' )
{
sb.append( "%20" );
}
else
{
sb.append( arr[i] );
}
}
}
private static String applyReplaceOperationWithCount(String str) {
if (StringUtils.isEmpty(str)) { //if string is null or empty, return it
return str;
}
char[] strChar = str.toCharArray();
int count = 0; //count spaces in the string to recalculate the array length
for (char c : strChar) {
if (c == ' ') {
count++;
}
}
if (count == 0) { // if there are no spaces in the string, return it
return str;
}
int length = strChar.length;
char[] newChar = new char[length + (count * 2)]; // 1 char will be replaced by 3 chars. So the new length should be count*2 larger than original
int index = 0;
for (char c : strChar) {
if (c != ' ') { // if char is not a space just push it in the next available location
newChar[index++] = c;
} else { // if char is a space just push %,2,0
newChar[index++] = '%';
newChar[index++] = '2';
newChar[index++] = '0';
}
}
return new String(newChar); // convert the new array into string
}
I am using matches and replaceAll it works well.
public class ReplaceSpaces {
public static void main(String[] args) {
String text = " Abcd olmp thv ";
if(text.matches(".*\\s+.*")){
System.out.println("Yes I see white space and I am replacing it");
String newText = text.replaceAll("\\s+", "%20");
System.out.println(newText);
}
else{
System.out.println("Nope I dont see white spaces");
}
}
}
Output
Yes I see white space and I am replacing it
%20Abcd%20olmp%20thv%20
public static String replaceSpaceInString(String string,String toreplace){
String replacedString = "";
if(string.isEmpty()) return string;
string = string.trim();
if(string.indexOf(" ") == -1)return string;
else{
replacedString = string.replaceAll("\\s+",toreplace);
}
return replacedString;
}
I have a String with name str.
str = "hi john";
Now I want to set j char to g. How can I do that?
You can't modify a String directly, but you can either use a StringBuilder:
str = "hi john";
StringBuilder sb = new StringBuilder(str);
sb.setCharAt(3,'g');
str = sb.toString();
.. or convert it to a char[] and back
str = "hi john";
char[] chars = str.toCharArray();
chars[3] = 'g';
str = new String(chars);
Two ways :
a. This will replace all occurances of 'j' with 'g'.
String str1 = "hi john";
System.out.println(str1); // prints - hi john
String str2 = str1.replace('j', 'g');
System.out.println(str2); // prints - hi gohn
b. If you wish to change the 'j' character only at one location in the string, you may want to do like this.
String str4 = replaceCharAt("hi john", 3,'g');
public static String replaceCharAt(String str1, int pos, char c) {
StringBuffer buf = new StringBuffer(str1);
buf.setCharAt(pos,c);
return buf.toString( );
}
// Here : pos = 3, char = 'g' and str1 = "hi john"
str = str.replace('j', 'g'); should do it for you.
str.replace('j','g');
as this java api shows
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#replace(char, char)
you can do like this
String str ="hi john"
syso(str.replace('j','g'));
Output will be hi gohn
You can use the substring. Look at :http://download.oracle.com/javase/tutorial/java/data/manipstrings.html
You can use something like this:
public static String replace(String _text, String _searchStr, String _replacementStr) {
// String buffer to store str
StringBuffer sb = new StringBuffer();
// Search for search
int searchStringPos = _text.indexOf(_searchStr);
int startPos = 0;
int searchStringLength = _searchStr.length();
// Iterate to add string
while (searchStringPos != -1) {
sb.append(_text.substring(startPos, searchStringPos)).append(_replacementStr);
startPos = searchStringPos + searchStringLength;
searchStringPos = _text.indexOf(_searchStr, startPos);
}
// Create string
sb.append(_text.substring(startPos,_text.length()));
return sb.toString();
}
public static int indexOf(String sb, String str, int start){
int index = -1;
if((start>=sb.length() || start<-1) || str.length()<=0) return index;
char[] tofind = str.toCharArray();
outer: for(;start<sb.length(); start++){
char c = sb.charAt(start);
if(c==tofind[0]){
if(1==tofind.length) return start;
inner: for(int i = 1; i<tofind.length;i++){ // start on the 2nd character
char find = tofind[i];
int currentSourceIndex = start+i;
if(currentSourceIndex<sb.length()){
char source = sb.charAt(start+i);
if(find==source){
if(i==tofind.length-1){
return start;
}
continue inner;
} else {
start++;
continue outer;
}
} else {
return -1;
}
}
}
}
return index;
}
String s;
int i = str.indexOf('j');
s = str.subString(0, i) + 'g' + str.subString(i + 1, str.length() - 1);