xor operation between chars - java

I have the following piece of Java code and while debugging in Eclipse, Windows 7, the variable 'xoredChar' shows no value at all, not null, not '', nothing.
char xoredChar = (char) (stringA.charAt(j)^stringB.charAt(j));
Why is that? I need to understand how can I do this xor operation between two characters in java. What am I missing?

Well, if the strings are equal you'll get back a \0 which is not a printable character. Try something like this,
String stringA = "A";
String stringB = "A";
int j = 0;
char xoredChar = (char) (stringA.charAt(j) ^ stringB.charAt(j));
System.out.printf("'%c' = %d\n", xoredChar, (int) xoredChar);
Output is
' ' = 0

If stringA and stringB are identical, then the XOR operation will yield xoredChar = 0.
A 0 is probably showing in your IDE as nothing since 0 is used as a string terminator in most instances.

As mentioned by the other answers, xoring the same characters results in a \0 value, which has no visual representation. Perhapse you are interested in a small application, which gives you and idea how XOR works on your strings:
public class Example {
public static void main(String[] args) {
String a = "abcde";
String b = a;
for (int idx = 0; idx < b.length(); idx++) {
System.out.printf("xoring <%s> [%s] with <%s> [%s]\n",
a.charAt(0), toBinaryString(a.charAt(0)),
b.charAt(idx), toBinaryString(b.charAt(idx)));
int c = (a.charAt(0) ^ b.charAt(idx));
System.out.printf("result is <%s> [%s]\n",
(char) c, toBinaryString(c));
}
}
}
Have fun!

Related

Caesar Cipher decoded wrongly in Java

I have implemented the Caesar Cipher algorithm in Java 8.
The Problem
Heute ist Freitag.
results into this encoded text using 22 as a key:
^{
{6
6{
w}D
Decoding this again gets me this output:
Heu
e is
Frei
ag.
The Code and description
It should be noted that my algorithm doesn't care about characters like '\n', meaning some characters might be translated to escape sequences or spaces etc.
This is also totally what I want to happen, thought it doesn't work.
public String encode(String txt, int key) {
if(key <= 0)
return txt;
String result = "";
for (int i = 0; i < txt.length(); i++) {
int x = (txt.charAt(i) + key) % 128;
result += (char) x;
}
System.out.println(result);
return result;
}
public String decipherM(String txt, int key) {
if(key <= 0)
return txt;
String result = "";
for (int i = 0; i < txt.length(); i++) {
int x = (txt.charAt(i) - key) % 128;
if(x < 0)
x += 128;
result += (char) x;
}
System.out.println(result);
return result;
}
The question
I would really like to know why it doesn't work with escape sequences or other non alphabetic characters.
Control characters have a defined meaning and text processing tools may retain the meaning or even remove those control characters not having a valid meaning, rather than retaining the exact byte representation.
Note that when you go beyond ASCII, this may even happen with ordinary characters, e.g. since you used a German sample text, you have to be aware that the two Unicode codepoint sequences \u00E4 and \u0061\u0308 are semantically equivalent, both referring to the character ä and you can not rely on text processing tool to retain both forms.
After all, there is a reason why encodings like Base 64 have been invented for lossless transfer of byte sequences through text processing tools.
For an encoding as simple as yours, it might be the best to simply forbid control characters in the source string and rotate only through the ASCII non-control character range:
public String encodeRotation(String txt, int distance) {
int first = ' ', last = 128, range = last - first;
while(distance<0) distance+=range;
if(distance == 0) return txt;
char[] buffer = txt.toCharArray();
for (int i = 0; i < txt.length(); i++) {
char c = buffer[i];
if(c<first || c>=last)
throw new IllegalArgumentException("unsupported character "+c);
buffer[i] = (char) ((c - first + distance) % range + first);
}
return String.valueOf(buffer);
}
public String decodeRotation(String txt, int key) {
return encodeRotation(txt, -key);
}
System.out.println(encodeRotation("Heute ist Freitag.", 22));
^{+*{6)*6\({*w}D
System.out.println(decodeRotation("^{+*{6)*6\\({*w}D", 22));
Heute ist Freitag.

Check if string is a palindrome after removing one character. My working solution is too slow

I cant seem to find a proper solution to an exercise. The exercise asks to create a method that returns true if a string can be a palindrome by removing one character. I have a solution that works but fails tests of large (100,000 character) strings because its exceeding the time limit of 1 second. Can somebody point me in the right direction?
I realize my approach is brute force and I'm sure there's a better way to solve it. I'm assuming my problem lies with the iteration.
public class Main {
public static boolean makePalindrome(String mjono) {
StringBuilder sb = new StringBuilder(mjono);
for (int i = 0; i < mjono.length(); i++) {
sb.deleteCharAt(i);
if(isPalindrome(sb.toString())){
return true;
} else {
sb.insert(i, mjono.charAt(i));
}
}
return false;
}
private static boolean isPalindrome(String string) {
return string.equals(new StringBuilder(string).reverse().toString());
}
public static void main(String[] args) {
System.out.println(makePalindrome("ABCBXA"));
System.out.println(makePalindrome("ABCBAX"));
System.out.println(makePalindrome("ABCXBA"));
System.out.println(makePalindrome("ABCDE"));
System.out.println(makePalindrome("BAAAAC"));
}
}
These are the tests it fails:
#Test(timeout=1000)
public void suuri2() {
int n = 100000;
char[] t = new char[n];
for (int i = 0; i < n; i++) t[i] = 'A';
t[12345] = 'B';
testaaSuuri(new String(t), true);
}
#Test(timeout=1000)
public void suuri3() {
int n = 100000;
char[] t = new char[n];
for (int i = 0; i < n; i++) t[i] = 'A';
t[12345] = 'B';
t[54321] = 'C';
testaaSuuri(new String(t), false);
}
Thanks in advance.
Well, there's of course the naive solution running in O(n ^ 2) by trying each possibility to remove one char.
But we can certainly do better:
We can define a palindrome recursively:
palindrome = x.palindrome.x | x | x.x , where x is an arbitrary token
So how does that help us? Pretty simple: we can derive a rules that allow checking whether the string is palindromic in O(n).
A palindrome consists of a char c, followed by a string that must be empty or palindromic, followed by another c, if it's longer than 1 char. If it's of length 1, it's automatically palindromic.
Thus, the last character must be equal to the first, the second to the second to the last, and so on. So basically:
boolean isPalindrome(String s){
for(int i = 0 ; i < s.length() / 2 ; i++)
if(s.charAt(i) != s.charAt(s.length() - i - 1))
return false;
return true;
}
We have to alter this rule a bit, since once we may remove a single character. This introduces splitting the whole problem into two parts, as we can see from a definition:
palindrome_1 = s.x.palindrome.reverse(s) | s.palindrome.x.reverse(s) | palindrome
As we can easily see, this contains the original palindrome-definition, but in addition allows introduction of one additional char x.
static boolean isPalindrome_1(String s){
for(int i = 0 ; i < s.length() / 2 ; i++)
if(s.charAt(i) != s.charAt(s.length() - i - 1))
return isPalindrome(s , i + 1 , s.length() - i - 1) ||
isPalindrome(s , i , s.length() - i - 2);
return true;
}
static boolean isPalindrome(String s , int lower , int upper){
while(lower < upper){
if(s.charAt(lower) != s.charAt(upper))
return false;
lower++;
upper--;
}
return true;
}
An explanation/or at least an attempt to explain this:
This piece of code:
if(s.charAt(i) != s.charAt(s.length() - i - 1))
return isPalindrome(s , i + 1 , s.length() - i - 1) ||
isPalindrome(s , i , s.length() - i - 2);
Is required, if the definition of palindrome doesn't apply to our input-string. In that case, we have to check two possibilities, how the code was built:
s.x.palindrome.reverse(s)
s.palindrome.x.reverse(s)
If the definition of palindrome doesn't apply, we have reached a point, were we have to ommit either the character of at the start of the remaining string (x.palindrome) or the end of the remaining string (palindrome.x) and see, if the rest matches the definition of a palindrome. This is done by calling isPalindrome(...) with two different substrings, that are cut by one character at either the start or the end of the remaining string.
An few examples of how this code works:
A B C D E F E D C B A
| | portion that runs inside isPalindrome_1
A B D E F E D C B A
| | | | portion that can be checked inside isPalindrome_1
| | isPalindrome(s , i , s.length() - i - 2)
| | isPalindrome(s , i + 1 , s.length() - i - 1)
As we can see in the second example, the code searched for the first pair of chars that isn't equal. At this point, we have two substrings to search further, which each ommit one character, either at the beginning or the end of the string.
Efficiency:
This code runs in-place - there are never made any copies of the input-string. Runtime is O(n) (O(2 * n) to be precise). Building a faster solution won't be possible - at least until we get quantum computers ;)
Hint 1: since this is an exercise, posting solutions is inappropriate. (It detracts from the learning experience of doing the exercise yourself.)
Hint 2: The following operations are all O(N) for an N character String or StringBuilder:
Adding or removing a character from a StringBuilder
Creating a new StringBuilder from an existing StringBuilder
Reversing a StringBuilder
Creating a String from a StringBuilder (toString())
Comparing two equal or "almost equal" String objects.
(In most cases you copy or compare N characters. For insertion and deletion, you copy on average 0.5 N characters assuming that the buffer does not need to grow, but that is still O(N). For equals ... it is complicated, but the worst-case is clearly O(N).)
So a fast palindrome tester for large strings needs to avoid these operations.
Hint 3: you can treat the string as an array of characters, either by converting it into a char[] or using charAt(...).
Hint 4: you don't have to physically remove the char from the string. You can just get your algorithm to pretend it isn't there.
We can solve this using LCS(Longest Common Sub-sequence).
LCS tells us the length of the longest sub-sequence in two strings.
boolean isPalindromAfterRemovingOneChar(String s) {
int lengthOfLCS = lcs(s, s.reverse(), s.length());
return (s.length()- lengthOfLCS) == 1;
}
function test(s) {
const check = isPalindrome(s)
if (!check) {
const arr = s.split('')
const arrCheck = []
arr.forEach((element, i) => {
if (element !== arr[arr.length - i - 1]) {
const news = Array.from(arr)
console.log(arr, news.splice(i, 1))
isPalindrome(news.join(''))
}
});
console.log('arrCheck', arrCheck)
}
function isPalindrome(s) {
var reversedString = s.split("").reverse().join("");
if (s === reversedString) {
console.log('this string is palindrome', s)
return true
} else {
console.log('no')
return false
}
test('aaab')
Only need to compare the first half to the second half. Don't waste time reversing the whole String either.
private boolean isPalindrome(String string) {
char[] values = string.toCharArray();
for (int i = 0; i < values.length / 2; i++) {
if (values[i] != values[values.length - 1 - i])
return false;
}
return true;
}

Shifting characters in a string to the left

I'm new to Stack Overflow and I have a lab question for a programming class that's been eluding me. The problem requires us to shift the elements of a string s to the left k times. For instance, if the input is "Hello World" and 3, it would output "lo WorldHel"). It also has to work relatively efficiently for very large values of k. This is what I have so far:
String cyclicLeftShift(String s, int k){
String result="";
for(int i=0;i<k;i++){
result = s.substring(1, s.length() - 1) +s.charAt(0);
s=result;
}
return s;
}
My major issue is that the last character of the original string keeps getting overwritten by the subsequent iterations of the loop. I've tried a great number of permutations, including converting the whole thing to arrays (which violates the efficiency restriction in the original problem). I feel like there's just a tiny thing I'm not getting, and I was wondering if someone could give me a nudge in the right direction?
Thank you!
What you want is to split the string at position k and merge both parts together again but in reverse order.
The main problem is that k may be greater than or equal to the size of your string. So you need to bring k into a valid range again.
public static String cyclicLeftShift(String s, int k){
k = k%s.length();
return s.substring(k) + s.substring(0, k);
}
Testing the method:
public static void main(String[] args)
{
String test = "Hello World";
for(int i = 0; i < test.length()*3; i++)
System.out.println(cyclicLeftShift(test, i));
}
Output:
Hello World
ello WorldH
llo WorldHe
lo WorldHel
o WorldHell
WorldHello
WorldHello
orldHello W
rldHello Wo
ldHello Wor
dHello Worl
Hello World
ello WorldH
llo WorldHe
lo WorldHel
o WorldHell
WorldHello
WorldHello
orldHello W
rldHello Wo
ldHello Wor
dHello Worl
Hello World
ello WorldH
llo WorldHe
lo WorldHel
o WorldHell
WorldHello
WorldHello
orldHello W
rldHello Wo
ldHello Wor
dHello Worl
Try this one my boy:
String cyclicLeftShift(String s, int k) {
String result = s.substring(k);
for (int i = 0; i < k; i++) {
result += s.charAt(i);
}
return result;
}
Maybe I'm missing something, but can you not just mod k by the length of s to get n (number of characters to shift), then take the substring of [0,n) and append it to the substring [n, s.length() -1]?
e.g.:
String cyclicLeftShift(String s, int k){
String result="";
int n = k % s.length();
result = s.substring(n) + s.substring(0,n);
return result;
}
You can try this:
public static String cyclicLeftShift(String s, int k){
String result=s;
for(int i=0; i<k; i++){
result = result.substring(1) + result.charAt(0);
}
return result;
}
Here's an example via TutorialsPoint. Just click on compile then execute to see the result.
The arguments to String.substring() are (beginIndex, endIndex), NOT (beginIndex, count). You need to pass s.length() instead of s.length()-1... Or you could do it one of the much faster ways that others are posting
Not sure if this solution is of help ! But it worked for me :) Well you could try it out!
class Main {
public static void main(String[] args) {
System.out.println("Moving left by n characters");
String str1 = moveCHaracters("Hellow World", 4);
System.out.println(str1);
}
public static String moveCHaracters(String s, int k) {
String result = s.substring(s.length() - (k));
int length = s.length() - k;
if (k > 0) {
for (int i = 0; i < length; i++) {
result = result + s.charAt(i);
}
}
return result;
}
}
A quick solution, just need to take care that the val to be shifted must not be OutOfBounds.
String shiftLeft(String inp, int val)
{
String shifted_str="";
shifted_str=inp.substring(val);
shifted_str+=inp.substring(0,val);
return shifted_str;
}

Finding the Number of Times an Expression Occurs in a String Continuously and Non Continuously

I had a coding interview over the phone and was asked this question:
Given a String (for example):
"aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc"
and an expression (for example):
"a+b+c-"
where:
+: means the char before it is repeated 2 times
-: means the char before it is repeated 4 times
Find the number of times the given expression appears in the string with the operands occurring non continuously and continuously.
The above expression occurs 4 times:
1) aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc
^^ ^^ ^^^^
aa bb cccc
2) aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc
^^ ^^ ^^^^
aa bb cccc
3) aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc
^^ ^^ ^^^^
aa bb cccc
4) aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc
^^ ^^ ^^^^
aa bb cccc
I had no idea how to do it. I started doing an iterative brute force method with lots of marking of indices but realized how messy and hard that would to code half way through:
import java.util.*;
public class Main {
public static int count(String expression, String input) {
int count = 0;
ArrayList<char[]> list = new ArrayList<char[]>();
// Create an ArrayList of chars to iterate through the expression and match to string
for(int i = 1; i<expression.length(); i=i+2) {
StringBuilder exp = new StringBuilder();
char curr = expression.charAt(i-1);
if(expression.charAt(i) == '+') {
exp.append(curr).append(curr);
list.add(exp.toString().toCharArray());
}
else { // character is '-'
exp.append(curr).append(curr).append(curr).append(curr);
list.add(exp.toString().toCharArray());
}
}
char[] inputArray = input.toCharArray();
int i = 0; // outside pointer
int j = 0; // inside pointer
while(i <= inputArray.length) {
while(j <= inputArray.length) {
for(int k = 0; k< list.size(); k++) {
/* loop through
* all possible combinations in array list
* with multiple loops
*/
}
j++;
}
i++;
j=i;
}
return count;
}
public static void main(String[] args) {
String expression = "a+b+c-";
String input = "aaksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc";
System.out.println("The expression occurs: "+count(expression, input)+" times");
}
}
After spending a lot of time doing it iteratively he mentioned recursion and I still couldn't see a clear way doing it recursively and I wasn't able to solve the question. I am trying to solve it now post-interview and am still not sure how to go about this question. How should I go about solving this problem? Is the solution obvious? I thought this was a really hard question for a coding phone interview.
Non-recursion algorithm that requires O(m) space and operates in O(n*m), where m is number of tokens in query:
#Test
public void subequences() {
String input = "aabbccaacccccbbd";
String query = "a+b+";
// here to store tokens of a query: e.g. {a, +}, {b, +}
char[][] q = new char[query.length() / 2][];
// here to store counts of subsequences ending by j-th token found so far
int[] c = new int[query.length() / 2]; // main
int[] cc = new int[query.length() / 2]; // aux
// tokenize
for (int i = 0; i < query.length(); i += 2)
q[i / 2] = new char[] {query.charAt(i), query.charAt(i + 1)};
// init
char[] sub2 = {0, 0}; // accumulator capturing last 2 chars
char[] sub4 = {0, 0, 0, 0}; // accumulator capturing last 4 chars
// main loop
for (int i = 0; i < input.length(); i++) {
shift(sub2, input.charAt(i));
shift(sub4, input.charAt(i));
boolean all2 = sub2[1] != 0 && sub2[0] == sub2[1]; // true if all sub2 chars are same
boolean all4 = sub4[3] != 0 && sub4[0] == sub4[1] // true if all sub4 chars are same
&& sub4[0] == sub4[2] && sub4[0] == sub4[3];
// iterate tokens
for (int j = 0; j < c.length; j++) {
if (all2 && q[j][1] == '+' && q[j][0] == sub2[0]) // found match for "+" token
cc[j] = j == 0 // filling up aux array
? c[j] + 1 // first token, increment counter by 1
: c[j] + c[j - 1]; // add value of preceding token counter
if (all4 && q[j][1] == '-' && q[j][0] == sub4[0]) // found match for "-" token
cc[j] = j == 0
? c[j] + 1
: c[j] + c[j - 1];
}
if (all2) sub2[1] = 0; // clear, to make "aa" occur in "aaaa" 2, not 3 times
if (all4) sub4[3] = 0;
copy(cc, c); // copy aux array to main
}
}
System.out.println(c[c.length - 1]);
}
// shifts array 1 char left and puts c at the end
void shift(char[] cc, char c) {
for (int i = 1; i < cc.length; i++)
cc[i - 1] = cc[i];
cc[cc.length - 1] = c;
}
// copies array contents
void copy(int[] from, int[] to) {
for (int i = 0; i < from.length; i++)
to[i] = from[i];
}
The main idea is to catch chars from the input one by one, holding them in 2- and 4-char accumulators and check if any of them match some tokens of the query, remembering how many matches have we got for sub-queries ending by these tokens so far.
Query (a+b+c-) is splitted into tokens (a+, b+, c-). Then we collect chars in accumulators and check if they match some tokens. If we find match for first token, we increment its counter by 1. If we find match for another j-th token, we can create as many additional subsequences matching subquery composed of tokens [0...j], as many of them now exist for subquery composed of tokens [0... j-1], because this match can be appended to every of them.
For example, we have:
a+ : 3 (3 matches for a+)
b+ : 2 (2 matches for a+b+)
c- : 1 (1 match for a+b+c-)
when cccc arrives. Then c- counter should be increased by b+ counter value, because so far we have 2 a+b+ subsequences and cccc can be appended to both of them.
Let's call the length of the string n, and the length of the query expression (in terms of the number of "units", like a+ or b-) m.
It's not clear exactly what you mean by "continuously" and "non-continuously", but if "continuously" means that there can't be any gaps between query string units, then you can just use the KMP algorithm to find all instances in O(m+n) time.
We can solve the "non-continuous" version in O(nm) time and space with dynamic programming. Basically, what we want to compute is a function:
f(i, j) = the number of occurrences of the subquery consisting of the first i units
of the query expression, in the first j characters of the string.
So with your example, f(2, 41) = 2, since there are 2 separate occurrences of the subpattern a+b+ in the first 41 characters of your example string.
The final answer will then be f(n, m).
We can compute this recursively as follows:
f(0, j) = 0
f(i, 0) = 0
f(i > 0, j > 0) = f(i, j-1) + isMatch(i, j) * f(i-1, j-len(i))
where len(i) is the length of the ith unit in the expression (always 2 or 4) and isMatch(i, j) is a function that returns 1 if the ith unit in the expression matches the text ending at position j, and 0 otherwise. For example, isMatch(15, 2) = 1 in your example, because s[14..15] = bb. This function takes just constant time to run, because it never needs to check more than 4 characters.
The above recursion will already work as-is, but we can save time by making sure that we only solve each subproblem once. Because the function f() depends only on its 2 parameters i and j, which range between 0 and m, and between 0 and n, respectively, we can just compute all n*m possible answers and store them in a table.
[EDIT: As Sasha Salauyou points out, the space requirement can in fact be reduced to O(m). We never need to access values of f(i, k) with k < j-1, so instead of storing m columns in the table we can just store 2, and alternate between them by always accessing column m % 2.]
Wanted to try it for myself and figured I could then share my solution as well. The parse method obviously has issues when there is indeed a char 0 in the expression (although that would probably be the bigger issue itself), the find method will fail for an empty needles array and I wasn't sure if ab+c- should be considered a valid pattern (I treat it as such). Note that this covers only the non-continous part so far.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Matcher {
public static void main(String[] args) {
String haystack = "aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc";
String[] needles = parse("a+b+c-");
System.out.println("Needles: " + Arrays.toString(needles));
System.out.println("Found: " + find(haystack, needles, 0));
needles = parse("ab+c-");
System.out.println("Needles: " + Arrays.toString(needles));
System.out.println("Found: " + find(haystack, needles, 0));
}
private static int find(String haystack, String[] needles, int i) {
String currentNeedle = needles[i];
int pos = haystack.indexOf(currentNeedle);
if (pos < 0) {
// Abort: Current needle not found
return 0;
}
// Current needle found (also means that pos + currentNeedle.length() will always
// be <= haystack.length()
String remainingHaystack = haystack.substring(pos + currentNeedle.length());
// Last needle?
if (i == needles.length - 1) {
// +1: We found one match for all needles
// Try to find more matches of current needle in remaining haystack
return 1 + find(remainingHaystack, needles, i);
}
// Try to find more matches of current needle in remaining haystack
// Try to find next needle in remaining haystack
return find(remainingHaystack, needles, i) + find(remainingHaystack, needles, i + 1);
}
private static String[] parse(String expression) {
List<String> searchTokens = new ArrayList<String>();
char lastChar = 0;
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
char[] chars;
switch (c) {
case '+':
// last char is repeated 2 times
chars = new char[2];
Arrays.fill(chars, lastChar);
searchTokens.add(String.valueOf(chars));
lastChar = 0;
break;
case '-':
// last char is repeated 4 times
chars = new char[4];
Arrays.fill(chars, lastChar);
searchTokens.add(String.valueOf(chars));
lastChar = 0;
break;
default:
if (lastChar != 0) {
searchTokens.add(String.valueOf(lastChar));
}
lastChar = c;
}
}
return searchTokens.toArray(new String[searchTokens.size()]);
}
}
Output:
Needles: [aa, bb, cccc]
Found: 4
Needles: [a, bb, cccc]
Found: 18
How about preprocessing aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc?
This become a1k1s1d1b1a2l1a1s1k1d1h1f1b2l1a1j1d1f1h1a1c4a1o1u1d1g1a1l1s1a2b2l1i1s1d1f1h1c4
Now find occurrences of a2, b2, c4.
Tried it code below but right now it gives only first possible match based of depth first.
Need to be changed to do all possible combination instead of just first
import java.util.ArrayList;
import java.util.List;
public class Parsing {
public static void main(String[] args) {
String input = "aksdbaalaskdhfbblajdfhacccc aoudgalsaa bblisdfhcccc";
System.out.println(input);
for (int i = 0; i < input.length(); i++) {
System.out.print(i/10);
}
System.out.println();
for (int i = 0; i < input.length(); i++) {
System.out.print(i%10);
}
System.out.println();
List<String> tokenisedSearch = parseExp("a+b+c-");
System.out.println(tokenisedSearch);
parse(input, 0, tokenisedSearch, 0);
}
public static boolean parse(String input, int searchFromIndex, List<String> tokensToSeach, int currentTokenIndex) {
if(currentTokenIndex >= tokensToSeach.size())
return true;
String token = tokensToSeach.get(currentTokenIndex);
int found = input.indexOf(token, searchFromIndex);
if(found >= 0) {
System.out.println("Found at Index "+found+ " Token " +token);
return parse(input, searchFromIndex+1, tokensToSeach, currentTokenIndex+1);
}
return false;
}
public static List<String> parseExp(String exp) {
List<String> list = new ArrayList<String>();
String runningToken = "";
for (int i = 0; i < exp.length(); i++) {
char at = exp.charAt(i);
switch (at) {
case '+' :
runningToken += runningToken;
list.add(runningToken);
runningToken = "";
break;
case '-' :
runningToken += runningToken;
runningToken += runningToken;
list.add(runningToken);
runningToken = "";
break;
default :
runningToken += at;
}
}
return list;
}
}
Recursion may be the following (pseudocode):
int search(String s, String expression) {
if expression consists of only one token t /* e. g. "a+" */ {
search for t in s
return number of occurrences
} else {
int result = 0
divide expression into first token t and rest expression
// e. g. "a+a+b-" -> t = "a+", rest = "a+b-"
search for t in s
for each occurrence {
s1 = substring of s from the position of occurrence to the end
result += search(s1, rest) // search for rest of expression in rest of string
}
return result
}
}
Applying this to entire string, you'll get number of non-continuous occurrences. To get continuous occurrences, you don't need recursion at all--just transform expression into string and search by iteration.
If you convert the search string first with a simple parser/compiler so a+ becomes aa etc. then you can simply take this string and run a regular expression match against your hay stack. (Sorry, I'm no Java coder so can't deliver any real code but it is not really difficult)

Java string, insert a dash after every 8 characters, starting from the right [duplicate]

This question already has answers here:
Putting char into a java string for each N characters
(12 answers)
Closed 6 years ago.
What's the best way to insert a - (dash/minus character) after every 8 characters in a Java String, starting from the right?
Examples:
1111 -> 1111
111111111 -> 1-11111111
1111111111111111 -> 11111111-11111111
100001111111111111111 -> 10000-11111111-11111111
My attempt, to show that I have tried doing it myself (a comment below asks: "is this homework?":
import junit.framework.TestCase;
public class InsertCharacterAfterEveryNCharacters extends TestCase {
public static String insertSpacerAfterNCharactersFromTheRight(char spacer,
int spacing, String string) {
final int length = string.length();
final int newStringCapacity = length + (int) Math.ceil(length / (double) spacing);
StringBuilder stringBuilder = new StringBuilder(newStringCapacity);
for (int i = length - 1; i >= 0; i--) {
stringBuilder.append(string.charAt(i));
if (i % spacing == 0 && i > 0) {
stringBuilder.append(spacer);
}
}
return stringBuilder.toString();
}
public static void testInsertSpacerAfterNCharactersFromTheRight() {
assertEquals("", insertSpacerAfterNCharactersFromTheRight('-', 8, ""));
assertEquals("1", insertSpacerAfterNCharactersFromTheRight('-', 8, "1"));
assertEquals("11", insertSpacerAfterNCharactersFromTheRight('-', 8, "11"));
assertEquals("11111111",
insertSpacerAfterNCharactersFromTheRight('-', 8, "11111111"));
assertEquals("1-11111111",
insertSpacerAfterNCharactersFromTheRight('-', 8, "111111111"));
assertEquals("11111111-11111111",
insertSpacerAfterNCharactersFromTheRight('-', 8, "1111111111111111"));
}
}
All answers seem a bit lot of code for what needs to be done. You could use a regular expression to do that.
Let's say you have a method that returns your formatted string.
A simple, clear example:
String myString = "00000000000111111111111100000000001111111000011000000";
String newString = myString.replaceAll("(.{8})(?!$)", "$1-");
return newString;
Above is equal to the following shorter notation:
return myString.replaceAll("(.{8})(?!$)", "$1-");
Another similar, short notation (in case of a fixed, hard-coded string):
return "00000000000111111111111100000000001111111000011000000".replaceAll("(.{8})(?!$)", "$1-");
Each piece of code resturns the following string:
00000000-00011111-11111111-00000000-00111111-10000110-00000
For more info on regular expressions, see for example http://www.regular-expressions.info/java.html
Hope this helps anyone in the future.
Edit note:
The last group doesn;t have 8 characters. However, if it would, it won't add another dash.
Build up a char[] from the original String:
String str = "100001111111111111111";
// add enough space for an additional "-" for every 8 chars:
char[] chars = new char[str.length() + (str.length() / 8)];
// this offset will give us the first "-" position from the LEFT:
int offset = str.length() % 8;
int idx = 0, strIdx = 0;
for (; strIdx < str.length(); idx++, strIdx++)
{
if (((strIdx % 8) == offset) && (strIdx != 0))
chars[idx++] = '-';
chars[idx] = str.charAt(strIdx);
}
String str2 = new String(chars);
System.out.println(str2);
Or you could use a StringBuilder, which could involve (length / 8) array copy operations:
StringBuilder str = new StringBuilder("100001111111111111111");
int idx = str.length() - 8;
while (idx > 0)
{
str.insert(idx, "-");
idx = idx - 8;
}
System.out.println(str.toString());
Output in either case:
10000-11111111-11111111
Note that this won't insert a hyphen at index 0, you'll need to adjust the code if that's necessary.
The above solutions are good but are very complicated and long, I wrote this and it works for your inputs.
public static String insertCharacterForEveryNDistanceFromRight(int distance, String original, char c){
StringBuilder sb = new StringBuilder();
char[] charArrayOfOriginal = original.toCharArray();
for(int ch = charArrayOfOriginal.length ; ch > 0 ; ch--){
if(ch % distance == 0 && ch != charArrayOfOriginal.length)
sb.append(c).append(charArrayOfOriginal[charArrayOfOriginal.length - ch]);
else
sb.append(charArrayOfOriginal[charArrayOfOriginal.length - ch]);
}
return sb.toString();
}
And call it like this...
String rightResult = InsertSpaces.insertCharacterForEveryNDistanceFromRight(8, "100001111111111111111", '-');
System.out.println(rightResult);
You cannot literally insert a - into an existing Java String because String are immutable. However, you can create a new String instance that meets your output format requirement.
Loop from the end index of your input string down to 0. For each iteration:
Insert the value at the current index to the beginning of a StringBuilder instance.
Use the modulo operator to see if you have inserted a multiple of 8 characters. If so, insert a dash.
If needed, use the "toString()" method of your StringBuilder instance to get a string.
Something like this perhaps?
for(int i = s.length() - 1; i > 0; i -= 8)
{
s = new StringBuffer(s).insert(i, "-").toString();
i--;
}

Categories