java regex negate with boundaries (square bracktes) - java

I would appreciate if anybody could help me with a JAVA regex requirement
I got a String like "/ABC/KLM[XYZ/ABC/KLM]/ABC"
I want to replace all ABC not surround by square brackets.
In this case only the first and last ABC should be found.
But not ABC in the middle because it is surrounded with square brackets

You cannot do this without a recursive regular expression. Java does not support this within the standard libraries, but flavours of regex found in Perl or .NET do. This is in essence the same problem as trying to match content within HTML tags - by far the easiest way to do it is using a stack-based parser.

Solution is here:
public class MergeParentAndChildXPATH {
public static void main(String[] args) {
String substringToBeFound = "ABC";
String toReplayceWith = "XXX";
String xPathFromExcel = "/UTILMD/ABC/[XYZ/ABC/KLM]KLM[XYZ/ABC/[XYZ/ABC/KLM]KLM]/ABC";
System.out.println("original String\t"+xPathFromExcel);
String manupulatedString = mergeParentAndChildXPATH(substringToBeFound, toReplayceWith,xPathFromExcel);
System.out.println("manipulated String\t"+manupulatedString);
}
public static String mergeParentAndChildXPATH(String substringToBeFound, String toReplayceWith, String xPathFromExcel ) {
StringBuffer sbManipulatedString = new StringBuffer();
int lengthABC = substringToBeFound.length();
CharStack charStack = new CharStack();
String substringAfterMatch = "";
while (xPathFromExcel.indexOf(substringToBeFound)>-1) {
int matchStartsAt = xPathFromExcel.indexOf(substringToBeFound);
int matchEndssAt = xPathFromExcel.indexOf(substringToBeFound)+lengthABC;
String substringBeforeMatch = xPathFromExcel.substring(0, matchStartsAt);
substringAfterMatch = xPathFromExcel.substring(matchStartsAt+lengthABC);
String substringMatch = xPathFromExcel.substring(matchStartsAt, matchEndssAt);
// System.out.println("Loop Count\t"+loopCount);
// System.out.println("substringBeforeMatch\t"+substringBeforeMatch);
// System.out.println("substringAfterMatch\t"+substringAfterMatch);
// System.out.println("starts "+matchStartsAt+ " ends "+matchEndssAt);
// System.out.println("Output of match: "+substringMatch);
// now tokenize the string till match is reached and memorize brackets via Stack
String sTokenize = xPathFromExcel;
for (int i = 0; i < matchStartsAt; i++) {
char ch = sTokenize.charAt(0);
// System.out.println(ch);
// System.out.println(sTokenize.substring(0,1));
if (ch == '[') {
charStack.push(ch);
}
if (ch == ']') {
charStack.pop();
}
sTokenize = sTokenize.substring(1);
}//for
if (charStack.empty()) {
substringMatch = substringMatch.replaceAll(substringMatch, toReplayceWith);
}
//
sbManipulatedString.append(substringBeforeMatch + substringMatch);
// System.out.println("manipulatedString\t"+sbManipulatedString.toString());
xPathFromExcel = substringAfterMatch;
// System.out.println("remaining String\t"+substringAfterMatch);
}
return (sbManipulatedString.toString()+substringAfterMatch);
}
}
import java.util.Stack;
public class CharStack {
private Stack theStack;
CharStack() {
theStack = new Stack();
}
public char peek() {
Character temp = (Character) theStack.peek();
return temp.charValue();
}
public void push(char c) {
theStack.push(new Character(c));
}
public char pop() {
char temp = (Character) theStack.pop();
return temp;
}
public boolean empty() {
return theStack.empty();
}
}

Related

Java - How to decode a string recursively

I need to decode a string recursively encoded as count followed by substring
An encoded string (s) is given, the task is to decode it. The pattern in which the strings are encoded is as follows.
Examples:
Input : str[] = "1[b]"
Output : b
Input : str[] = "2[ab]
Output : abab
Input : str[] = "2[a2[b]]"
Output : abbabb
Input : str[] = "3[b2[ca]]"
Output : bcacabcacabcaca
Below is the code I tried to achieve the same. All I know is it can be solved using two stacks.
public class Main {
public static void main(String[] args) {
Stack<Interger> s1 = new Stack();
Stack<String> s2 = new Stack();
String result = "";
for(int i = 0; i < args.length; i++){
if(Interger.parseInt(args[i]) == 0){
s1.push(args[i]);
}
if(args[i] == 0){
if(args[i] == ']'){
result = s2.pop();
}
if(args[i] == '['){
continue;
}
s2.push(args[i])
}
}
}
}
Can anyone help me what is the efficient way to write code in order to get the expected output?
How to decode a string recursively
You need to define a base case and recursive case:
Base case - the given string doesn't contain square brackets [], therefore no need to process it. The return value is the given string itself.
Recursive case - we need to determine the indices of opening [ and closing brackets ] and based on that contract a new string.
That's how it could be implemented:
public static String decode(String str) {
int startOfBrackets = str.indexOf('[');
if (startOfBrackets == -1) { // base case there's no square brackets in the string
return str;
}
int startOfDigits = getFirstDigitsPosition(str);
int repeatNum = Integer.parseInt(str.substring(startOfDigits, startOfBrackets));
return str.substring(0, startOfDigits) +
decode(str.substring(startOfBrackets + 1, str.length() - 1)).repeat(repeatNum);
}
public static final Pattern SINGLE_DIGIT = Pattern.compile("\\d");
public static int getFirstDigitsPosition(String str) {
Matcher matcher = SINGLE_DIGIT.matcher(str);
if (matcher.find()) {
return matcher.start();
}
return -1;
}
main()
public static void main(String[] args) {
System.out.println(decode("1[b]"));
System.out.println(decode("2[ab]"));
System.out.println(decode("2[a2[b]]"));
System.out.println(decode("3[b2[ca]]"));
}
Output:
abab
abbabb
bcacabcacabcaca

Reduction of duplicate words prior to uppercase or lowercase

Main
public class Main
{
public static void main(String[] args)
{
System.out.println(Dupe.Eliminate("Testing UppeR and loweR"));
System.out.println(Dupe.Eliminate("UppeR is BetteR"));
}
}
Class
public class Dupe
{
public static String Eliminate(String input)
{
char[] chrArray = input.toCharArray();
String letter ="";
for (char value:chrArray){
if (letter.indexOf(value) == -1){
letter += value;
}
}
return letter;
}
}
I am trying to eliminate duplicate letters e.g. Hello would be Helo. Which I have achieved, however, what I want to implement is that it won't matter if it's uppercase or lowercase, it will still be classed as a duplicate so Hehe would be He, not Heh. Should I .equals... each individual letter or is there an efficient way? sorry for asking if it's simple question for you guys.
This is how I would approach this. This might not be the most efficient way to do it, but you can try this.
public class Main
{
public static void main(String[] args)
{
System.out.println(Dupe.Eliminate("Testing UppeR and loweR"));
}
}
class Dupe
{
public static String Eliminate(String input)
{
char[] chrArray = input.toCharArray();
String letter ="";
for(int index = 0; index < chrArray.length; index++)
{
int j = 0;
boolean flag = true;
//this while loop is used to check if the next character is already existed in the string (ignoring the uppercase or lowercase)
while(j < letter.length())
{
if((int)chrArray[index] == letter.charAt(j) || (int)chrArray[index] == ((int)letter.charAt(j)+32) ) //32 is because the difference between the ascii value of the uppercase and lowercase letter is 32
{
flag = false;
break;
}
else
j++;
}
if(flag == true)
{
letter += chrArray[index];
}
}
return letter;
}
}
you can have 2 checks in place with upper case and lower case characters:
public static String Eliminate(String input)
{
char[] chrArray = input.toCharArray();
String letter ="";
for (char value:chrArray){
if (letter.indexOf(value.toLowerCase()) == -1 && letter.indexOf(value.toUpperCase()) == -1){
letter += value;
}
}
return letter;
}
Here you go, this will replace all duplicate characters no matter how many in the sequence.
public static void main(String[] args)
{
String duped = "aaabbccddeeffgg";
final Pattern p = Pattern.compile("(\\w)\\1+");
final Matcher m = p.matcher(duped);
while (m.find())
System.out.println("Duplicate character " + (duped = duped.replaceAll(m.group(), m.group(1))));
}
If you are looking for duplicates like: abacd to replace both a's, try this as the regex given in Pattern.compile(".*([0-9A-Za-z])\\1+.*")
Here's another (stateful) way to do it:-
String s = "Hehe";
Set<String> found = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
String result = s.chars()
.mapToObj(c -> "" + (char) c)
.filter(found::add)
.collect(Collectors.joining());
System.out.println(result);
Output: He

Using StringBuilder getting null as output

I am doing one coding question in which I try to decrypt the input string. The procedure for the decryption is:
from 0 to 9 it represent alphabets from a to i.
then 10# represent j, 11# represent k and so.
import java.util.HashMap;
public class Julia {
public static void main(String[] args) {
String s="10#21#12#91";
Julia obj=new Julia();
String result=obj.decrypt(s);
System.out.println(result);
}
public String decrypt(String msg)
{
HashMap<String,Character> hs=new HashMap<>();
hs.put("1",'a');
hs.put("2",'b');
hs.put("3",'c');
hs.put("4",'d');
hs.put("5",'e');
hs.put("6",'f');
hs.put("7",'g');
hs.put("8",'h');
hs.put("9",'i');
hs.put("10",'j');
hs.put("11",'k');
hs.put("12",'l');
hs.put("13",'m');
hs.put("14",'n');
hs.put("15",'o');
hs.put("16",'p');
hs.put("17",'q');
hs.put("18",'r');
hs.put("19",'s');
hs.put("20",'t');
hs.put("21",'u');
hs.put("22",'v');
hs.put("23",'w');
hs.put("24",'x');
hs.put("25",'y');
hs.put("26",'x');
StringBuilder n=new StringBuilder();
for(int i=msg.length()-1;i>=0;i--)
{
if(msg.charAt(i)=='#' && i>=2)
{
StringBuilder s=new StringBuilder().append(msg.charAt(i-2)).append(msg.charAt(i-1));
System.out.println(s);
n.append(hs.get(s));
System.out.println(n);
i=i-2;
}
else
{
n.append(hs.get(msg.charAt(i)));
}
}
return n.toString();
}
}
That is code I wrote. But the output I am getting is nullnullnullnullnull.
I think the issue is with StringBuilder. Can anyone help me with that and explain the concept? If someone has better solution please guide.
You should not use data (a map) when you could have used a simple formula.
My suggestion:
import java.util.ArrayList;
import java.util.List;
public final class Julia {
public static void main(final String[] args) {
final String s = "10#21#12#91";
final String result = decrypt(s);
System.out.println(result);
}
private static String decrypt(final String s) {
final List<Integer> crypt = new ArrayList<>();
final String[] groups = s.split("#");
for (int i = 0; i < groups.length; i++) {
final String group = groups[i];
int j = 0;
// Special case for last group
if ((i == (groups.length - 1)) && !s.endsWith("#")) {
j = group.length();
}
if (group.length() > 2) {
j = group.length() - 2;
}
for (int k = 0; k < j; k++) {
crypt.add(Integer.valueOf(group.substring(k, k + 1)));
}
if (j < group.length()) {
crypt.add(Integer.valueOf(group.substring(j, group.length())));
}
}
final StringBuilder n = new StringBuilder(crypt.size());
for (final Integer c : crypt) {
final char d = (char) (('a' + c) - 1);
n.append(d);
}
return n.toString();
}
}
Please note that there are two mistakes in the question: The letter a is 1, not zero, and the value for 26 is z, not x. The latter error is typical when you use data where a formula would do.
Since you are learning, I would note that the decrypt methods - both my suggestion and yours - should be static since they do not use any fields, so the instantiation is not necessary.
This is Pattern Matching problem which can be solved by Regex.
Your code has some bugs and those are already pointed out by others. I don't see any solution which looks better than a simple regex solution.
Below regex code will output 'julia' for input '10#21#12#91'.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Julia {
public static void main(String[] args) {
String s="10#21#12#91";
Julia obj=new Julia();
String result=obj.decrypt(s);
System.out.println(result);
}
public String decrypt(String msg)
{
Pattern regex = Pattern.compile("((\\d\\d#)|(\\d))");
Matcher regexMatcher = regex.matcher(msg);
StringBuffer result = new StringBuffer();
while (regexMatcher.find())
regexMatcher.appendReplacement(result, getCharForNumber(Integer.parseInt(regexMatcher.group(1).replace("#",""))));
return result.toString();
}
private String getCharForNumber(int i) {
return i > 0 && i < 27 ? String.valueOf((char)(i + 96)) : null;
}
}
I hope it helps.
hs.get(s) will always return null, since s is not a String.
Try hs.get(s.toString())
hs.get(msg.charAt(i)) will also always return null, since you are passing a char to get instead of String.
There may also be logic problems in your code, but it's hard to tell.
Optimized version of your code
public class Main {
public static void main(String[] args) {
String cipher = "10#21#12#91";
System.out.print(decrypt(cipher));
//output : julia
}
static String decrypt(String cipher) {
//split with # to obtain array of code in string array
String[] cipher_char_codes = cipher.split("#");
//create empty message
StringBuilder message = new StringBuilder();
//loop for each code
for (String code : cipher_char_codes) {
//get index of character
int index = Integer.parseInt(code);
if (index > 26) {
char[] pair = code.toCharArray();
for (int i = 0; i < pair.length; i++) {
int x = Integer.parseInt("" + code.charAt(i));
message.append((char) ('a' + ((x - 1) % 26)));
}
} else {
//map index into 1 to 26
//find ascii code and cast into char
message.append((char) ('a' + ((index - 1) % 26)));
}
}
return message.toString();
}
}
Regex is indeed the way to go, and the code proposed by Pirate_Jack can be improved. It calls the expensive regex two superfluous times (replace is a regex operation).
Following is a yet improved version:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Julia3 {
public static void main(final String[] args) {
final String s = "10#21#12#91";
final String result = decrypt(s);
System.out.println(result);
}
public static String decrypt(final String msg) {
final Pattern regex = Pattern.compile("((\\d\\d)(#)|(\\d))");
final Matcher regexMatcher = regex.matcher(msg);
final StringBuffer result = new StringBuffer();
String c;
while (regexMatcher.find()) {
if (regexMatcher.group(2) == null) {
c = regexMatcher.group(1);
} else {
c = regexMatcher.group(2);
}
result.append((char) ((Integer.parseInt(c) + 'a') - 1));
}
return result.toString();
}
}
This is not right :
hs.get(s)
s is a StringBuilder. It should be hs.get(Char)
Edit: an optional different solution:
public class Julia {
public static void main(String[] args) {
String s="10#21#12#91";
List<String> numbers = splitToNumbers(s);
Julia obj=new Julia();
String result=obj.decrypt(numbers);
System.out.println(result);
}
/**
*#param s
*#return
*/
private static List<String> splitToNumbers(String s) {
//add check s is not null
char[] chars = s.toCharArray();
char delimiter = '#';
List<String> numberAsStrings = new ArrayList<String>();
int charIndex = 0;
while (charIndex < (chars.length -3)) {
char theirdChar = chars[charIndex+2];
if(theirdChar == delimiter) {
numberAsStrings.add(""+chars[charIndex]+chars[charIndex+1]);
charIndex +=3;
}else {
numberAsStrings.add(""+chars[charIndex]);
charIndex ++;
}
}
//add what's left
while (charIndex < chars.length) {
numberAsStrings.add(""+chars[charIndex]);
charIndex++;
}
return numberAsStrings;
}
public String decrypt(List<String> numbersAsStings){
StringBuilder sb=new StringBuilder();
for (String number : numbersAsStings) {
int num = Integer.valueOf(number);
sb.append(intToChar(num-1));
}
return sb.toString();
}
private char intToChar(int num) {
if((num<0) || (num>25) ) {
return '?' ;
}
return (char)('a' + num);
}
}

Stacks dealing racognizng strings in a language, keep getting error, it's a array based implementation

I am trying to implement an algorithm "recongnizng strings in a languages "
L = {'w$w' : w is a possible empty string of characters other than $,
w' = reverse(w)}
I get an error saying where ch = aString[i]; : the type of expression must be an array type but resolved to string
also where stackTop = aStack.pop(); but here however it's asking to cast to char
'
import java.util.Stack;
public class Stacks
{
public static void main(String[] args){
boolean eval = isInLanguage("sod$dos");
System.out.println(eval);
}
static // astack.createStack();
boolean isInLanguage(String aString){
Stack<Character> aStack = new Stack<>();
int i = 0;
char ch = aString.charAt(i);
while (ch != '$') {
aStack.push(ch);
i++;
}
//Skip the $
++i;
// match the reverse of w
boolean inLanguage = true; // assume string is in language
while (inLanguage && i < aString.length()) {
char stackTop;
ch = aString.charAt(i);;
try {
stackTop = (char) aStack.pop();
if (stackTop == ch) {
i++;
} else {
// top of stack is not ch(Charecter do not match)
inLanguage = false; // reject string
}
} catch (StackException e) {
// aStack.poo() failed, astack is empty (first, half of Stirng
// is short than second half)
inLanguage = false;
}
}
if (inLanguage && aStack.isEmpty()) {
return true;
}
else{
return false;
}
}
}
'
I just made the necessary changes but now, it will compile but it doesnt seem to stop and doesn't output anything, i am expecting a true in the console
In java, you use aString.chatAt(i), not as you did. A String is not an array of chars, as it is in C.
Why don't you use java.util.Stack ?
import java.util.Stack;
and
Stack<Character> aStack = new Stack<>();
should do the work.
You cannot [] index into a String in Java. Try:
ch = aString.charAt(i);

Alternating string of characters and digits

I was given this problem to solve. I have only the slightest idea on how it should be implemented, and I'm all too new with programming and stuffs, and would love to hear your comments on this.
Say given a string in the form "abc1234defgh567jk89", and I must create a new string "a1b2c3d5e6f7j8k9".
Note that there are corresponding [digits] & [characters] group and since there may be more of one type over the other, the output has only matching sequence and ignore extra digits or characters in this case '4' & 'g' & 'h'.
I know I will have to use 2 sets of queues to store both types of elements, but I do not know how else to proceed from here.
Would appreciate if you could share a pseudocode or a Java(prefably) version, since I am learning thru this language now.
Thank you.
Pseudocode:
Queue letterQueue;
Queue numberQueue;
for (every character in the string) {
if (it's a letter) {
if (numberQueue is not empty) {
add the letters alternating into the buffer (stringbuilder), and purge buffers
}
add newest letter to letterqueue
}
if (it's a number) {
add newest letter to numberqueue
}
}
add any remaining unprocessed letters to the queue (this will happen most of the time)
return contents of string buffer
You will need:
Queue, probably a LinkedList
StringBuilder
String.toCharArray
Character
Code:
import java.util.LinkedList;
import java.util.Queue;
public class StringTest {
private static String str ="abc1234defgh567jk89";
private static String reorganize(String str) {
Queue<Character> letterQueue = new LinkedList<>();
Queue<Character> numberQueue = new LinkedList<>();
StringBuilder s = new StringBuilder();
for (char c : str.toCharArray()) {
if(Character.isLetter(c)) {
if (!numberQueue.isEmpty()) processQueues(letterQueue, numberQueue, s);
letterQueue.offer(c);
} else if(Character.isDigit(c)) {
numberQueue.offer(c);
}
}
processQueues(letterQueue, numberQueue, s);
return s.toString();
}
private static void processQueues(Queue<Character> letterQueue, Queue<Character> numberQueue, StringBuilder s) {
while(!letterQueue.isEmpty() && !numberQueue.isEmpty()) {
s.append(letterQueue.poll());
s.append(numberQueue.poll());
}
letterQueue.clear();
numberQueue.clear();
}
public static void main(String... args) {
System.out.println(reorganize(str));
}
}
See this hint:
String str = "abc1234defgh567jk89";
String c = str.replaceAll("\\d", ""); // to store characters
String d = str.replaceAll("\\D", ""); // to store digits
Try this:
public static void main(String[] args) {
String str = "abc1234defgh567jk89";
String c = str.replaceAll("\\d", "");
String d = str.replaceAll("\\D", "");
String result = "";
int j = 0, k = 0;
int max = Math.max(c.length(), d.length());
for (int i = 0; i < max; i++) {
if (j++ < c.length())
result = result + c.charAt(i);
if (k++ < d.length())
result = result + d.charAt(i);
}
System.out.println(result);
}
Output:
a1b2c3d4e5f6g7h8j9k

Categories

Resources