Checking for consecutively repeated characters in java - java

I am quite new to java. I am wondering if it is possible to check for a certain number of consecutively repeated characters (the 'certain number' being determined by the user) in a string or an index in a string array. So far I have tried
int multiple_characters = 0;
String array1 [] = {"abc","aabc","xyyyxy"};
for (int index = 0; index < array1.length;i++){
for (int i = 0;i<array1[index].length;i++){
if (array1[index].charAt(i) == array1[index].charAt(i+1)){
multiple_characters++;
}
}
}
But with this I get a StringIndexOutOfBounds error. I tried fixing this by putting in an extra if statement to make sure i was not equal to the array1[index].length, but this still threw up the same error. Other than the manual and cop-out method of:
if ((array1[index].charAt(i) == array1[index].charAt(i+1) && (array1[index].charAt(i) == array1[index].charAt(i+2))
and repeating however many times, (which would not be great for quick changes to my code), I can't seem to find a solution.

For the inner for loop (the one with the i variable), you're then calling string.charAt(i+1) where ii loops from 0 to the length of that string.
No wonder you get an index array out of bounds exception, you're asking for the character AFTER the last.
I advise that you try to understand the exception, and if you can't, debug your code (step through it, one line at a time, and if you don't know how to use a debugger, add println statements, checking what the code does what with you think it does. There where your code acts differently from your expectation? That's where the bug is).
This plan of 'oh, it does not work, I'll just chuck it out entirely and find another way to do it' is suboptimal :) – go back to the first snippet, and just fix this.

You are getting StringIndexOutOfBoundsException because you are trying to access string.charAt(i + 1) where i goes up to the highest index (i.e. string.length() - 1) of string.
You can do it as follows:
class Main {
public static void main(String[] args) {
int multiple_characters = 0;
int i;
String array1[] = { "abc", "aabc", "xyyyxy" };
for (int index = 0; index < array1.length; index++) {
System.out.println("String: " + array1[index]);
for (i = 0; i < array1[index].length() - 1; i++) {
multiple_characters = 1;
while (array1[index].charAt(i) == array1[index].charAt(i + 1) && i < array1[index].length() - 1) {
multiple_characters++;
i++;
}
System.out.println(array1[index].charAt(i) + " has been repeated consecutively " + multiple_characters
+ " time(s)");
}
if (multiple_characters == 1) {
System.out.println(array1[index].charAt(i) + " has been repeated consecutively 1 time(s)");
}
System.out.println("------------");
}
}
}
Output:
String: abc
a has been repeated consecutively 1 time(s)
b has been repeated consecutively 1 time(s)
c has been repeated consecutively 1 time(s)
------------
String: aabc
a has been repeated consecutively 2 time(s)
b has been repeated consecutively 1 time(s)
c has been repeated consecutively 1 time(s)
------------
String: xyyyxy
x has been repeated consecutively 1 time(s)
y has been repeated consecutively 3 time(s)
x has been repeated consecutively 1 time(s)
y has been repeated consecutively 1 time(s)
------------

If I was to look for repeated characters, I would go the regular expression route. For example to look for repeated a characters (repeated twice in this example), you could have:
import java.util.regex.Pattern;
public class Temp {
public static void main(final String[] args) {
String array1 [] = {"abc","aabc","xyyyxy"};
for (String item : array1){
if (Pattern.compile("[a]{2}").matcher(item).find()) {
System.out.println(item + " matches");
}
}
}
}
In this extract, the reg exp is "[a]{2}" which looks for any sequence of a characters repeated twice.
Of course more complicated regular expressions are required for more complex matches, good resources to explain this may be found here:
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/regex/Pattern.html
Another point is that for efficiencies sake, it is often practise to move the:
Pattern.compile(*Pattern*)
outside of the method call, e.g. to a final static field
This stack overflow:
RegEx No more than 2 identical consecutive characters and a-Z and 0-9
gives quite a detailed description of the regular expression issues involved with this problem.

Related

Euclid's algorithm shows wrong conclusion

Homework of mine is to create and Euclid's algorithm in java. The task binds me to use both while-loop and if statement. Futhermore - if statement has to be placed inside while-loop.
During this task i faced already infinity-loop problem, somehow manage to get pass it. Now my Euclid's algorithm is giving multiple answers (instead of one) and futhermore they are wrong...
I have searched a couple of topics over here, but none of answers shown in there gave me an answer. I tried to rewrite whole code, and also diffrent conditions for while-loop and if statement.
import java.lang.*;
class EuklidesAlgorithm {
public static void main (String[] args) throws java.lang.Exception{
int a = 25648;
int b = 15468;
while (a % b != 0 ){
int modulo = a % b;
if (modulo == 0){
break;
}else {
modulo = a % b;
System.out.println(" Checking for GCD");
a = b;
b = modulo;
}
System.out.println(" Number " + b + " is GDC of numbers(" + a + "," + b + ").");
}
}
}
I would like it to give a single answer what is GCD for a and b.
First of all the condition :
modulo==0
will alaways be false inside the loop...
and you dont have to change variable prices inside the loop and you also don't have to print answers in every loop so...
the if statement is probably goind to be used to check if any of those two numbers is 0 or if the result is 0 but you can do both

Cut out different elements from a string and put them into a list

Here's updated code. For those following along the question edits contains the original question.
if (0 != searchString.length()) {
for (int index = input.indexOf(searchString, 0);
index != -1;
index = input.indexOf(searchString, eagerMatching ? index + 1 : index + searchString.length())) {
occurences++;
System.out.println(occurences);
indexIN=input.indexOf(ListStringIN, occurences - 1) + ListStringIN.length();
System.out.println(indexIN);
System.out.println(ListStringIN.length());
indexOUT=input.indexOf(ListStringOUT, occurences - 1);
System.out.println(indexOUT);
Lresult.add(input.substring(indexIN, indexOUT));
System.out.println();
}
}
As you can see, I gave me out the index numbers
My code works well with only one Element
But when I write something like this: %%%%ONE++++ %%%%TWO++++
There's this exception:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: begin 16, end 7, length 23
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3410)
at java.base/java.lang.String.substring(String.java:1883)
at com.DMMS.Main.identify(Main.java:81)
And I found out that the indexIN changes in the Start of the second String but not the indexOUT
I couldn't find out why
When you look at your code you can notice: in the first loop that counts the number of occurrences, your code "knows" that it has to use that version of indexOf() that relies on offsets within the search strings.
In other words: you know that you have to search after previous "hits" when walking through your string.
But your second loop, the one that has to extract the actual things, there you are using indexOf() without that extra offset parameter. Therefore you keep "copying out" the same part repeatedly.
Thus: "simply" apply the same logic from loop 1 for loop 2!
Beyond that:
you don't need two loops for that. Counting occurrences and "copying out" the matching code ... can be done in one loop
and honestly: rewrite that first loop. This code is almost incomprehensible for human beings. A reader would have to sit down and read this 10, 20 times, and then run it in a debugger to understand what it is doing
I dit it!
Heres the code:
.........................
static String ListStringIN = "%%%%";
static String ListStringOUT = "++++";
........................
else if (input.contains(ListStringIN) && input.contains(ListStringOUT)) {
System.out.println("Identifiziere Liste...");
String searchString = ListStringIN;
int occurences = 0;
boolean eagerMatching = false;
if (0 != searchString.length()) {
for (int index = input.indexOf(searchString, 0); index != -1; index = input
.indexOf(searchString, eagerMatching ? index + 1 : index + searchString.length())) {
occurences++;
System.out.println(occurences);
indexIN=input.indexOf(ListStringIN, occurences - 1) + ListStringIN.length();
System.out.println(indexIN);
//indexOUT=input.indexOf(ListStringOUT, occurences);
//indexOUT=input.indexOf(ListStringOUT, occurences - 1);
indexOUT = input.indexOf(ListStringOUT, eagerMatching ? index + 1 : index + ListStringOUT.length());
System.out.println(indexOUT);
Lresult.add(input.substring(indexIN, indexOUT));
System.out.println();
}
}
//for (int i = 0; i <occurences; i ++) {
// Lresult.add(input.substring(input.indexOf(ListStringIN, 0) + ListStringIN.length(), input.indexOf(ListStringOUT)));
//}
result = Lresult.toString();
return result;
}
I hope this is useful for other people
#GhostCat Thanks for your advices!

Print out Yijing Hexagram Symbols

I encountered a problem while coding and I can't seem to find where I messed up or even why I get a wrong result.
First, let me explain the task.
It's about "Yijing Hexagram Symbols".
The left one is the original and the right one is the result that my code should give me.
Basically every "hexagram" contains 6 lines that can be either diveded or not.
So there are a total of
2^6 = 64 possible "hexagrams"
The task is to calculate and code a methode to print all possible combinations.
Thats what I have so far :
public class test {
public String toBin (int zahl) {
if(zahl ==0) return "0";
if (zahl ==1 ) return "1";
return ""+(toBin( zahl/2)+(zahl%2));
}
public void show (String s) {
for (char c : s.toCharArray()){
if (c == '1'){
System.out.println("--- ---");
}
if(c=='0'){
System.out.println("-------");
}
}
}
public void ausgeben (){
for(int i = 0 ; i < 64; i++) {
show (toBin(i));
}
}
}
The problem is, when I test the 'show'-methode with "10" I get 3 lines and not 2 as intended.
public class runner {
public static void main(String[] args){
test a = new test();
a.ausgeben();
a.show("10");
}
}
Another problem I've encoutered is, that since I'm converting to binary i sometimes have not enough lines because for example 10 in binary is 0001010 but the first "0" are missing. How can I implement them in an easy way without changing much ?
I am fairly new to all this so if I didn't explain anything enough or made any mistakes feel free to tell me.
You may find it easier if you use the Integer.toBinaryString method combined with the String.format and String.replace methods.
String binary = String.format("%6s", Integer.toBinaryString(zahl)).replace(' ', '0');
This converts the number to binary, formats it in a field six spaces wide (with leading spaces as necessary), and then replaces the spaces with '0'.
Well, there are many ways to pad a string with zeros, or create a binary string that is already padded with zeros.
For example, you could do something like:
public String padToSix( String binStr ) {
return "000000".substring( 0, 5 - binStr.length() ) + binStr;
}
This would check how long your string is, and take as many zeros are needed to fill it up to six from the "000000" string.
Or you could simply replace your conversion method (which is recursive, and that's not really necessary) with one that specializes in six-digit numbers:
public static String toBin (int zahl) {
char[] digits = { '0','0','0','0','0','0' };
int currDigitIndex = 5;
while ( currDigitIndex >= 0 && zahl > 0 ) {
digits[currDigitIndex] += (zahl % 2);
currDigitIndex--;
zahl /= 2;
}
return new String(digits);
}
This one modifies the character array ( which initially has only zeros ) from the right to the left. It adds the value of the current bit to the character at the given place. '0' + 0 is '0', and '0' + 1 is '1'. Because you know in advance that you have six digits, you can start from the right and go to the left. If your number has only four digits, well, the two digits we haven't touched will be '0' because that's how the character array was initialized.
There are really a lot of methods to achieve the same thing.
Your problem reduces to printing all binary strings of length 6. I would go with this code snippet:
String format = "%06d";
for(int i = 0; i < 64; i++)
{
show(String.format(format, Integer.valueOf(Integer.toBinaryString(i))));
System.out.println();
}
If you don't wish to print leading zeros, replace String.format(..) with Integer.toBinaryString(i).

Questions over BigInteger?

import java.math.BigInteger;
public class ProjectEuler {
public static void main(String[] args) {
BigInteger bi = new BigInteger("600851475143");
int div = 7;
while (bi.compareTo(new BigInteger("1")) != 0) {
while (bi.mod(new BigInteger(div + "")).compareTo(new BigInteger("0")) == 0) {
bi = bi.divide(new BigInteger(div + ""));
}
div += 2;
}
System.out.println("" + div);
}
}
I was just looking over one of the basic but famous problems of "What is the largest prime factor of the number 600851475143". I found this solution different, i have a couple of questions on how this works.
The first condition checks whether the number equals 1 or not. From there i am not able to understand the rest of the code.
new BigInteger(div +""). why do we concatenate + "" here?
How is the div = 7 decided?
The author decided to "hard-code" his knowledge of the number itself to decide that the first three primes are not among the divisors
The first condition checks whether the number equals 1 or not. From there i am not able to understand the rest of the code.
The rest of the code looks like this in "regular" integers:
while (bi % div == 0) {
bi /= div;
}
div += 2;
new BigInteger(div +"") why do we concatenate + "" here
That is a short way of making an object a String. BigInteger has a parameter that takes String, so the alternative to this approach would be calling Integer.toString(div).
Note that this is not the most efficient solution: one could speed this up by observing that you could stop trying to divide when you reach the square root of the original number, because you can be sure that the next divisor will be the number itself.
How is the div = 7 decided?
Probably the author noticed that the number isn't divisible by 2 nor 3 nor 5. To know how the author did this, he/she should have known this rules: Divisibility Rules and Tests
The first condition checks whether the number equals 1 or not. From there i am not able to understand the rest of the code.
The author is making sure that the number is not BigInteger("1") since it's dividing the number and storing the results in bi in the loop iterations. Note this:
bi = bi.divide(new BigInteger(div + ""));
new BigInteger(div +""). why do we concatenate + "" here?
It uses the BigInteger(String) constructor. The author n̶a̶i̶v̶e̶l̶y̶ makes a new String by adding the int with an empty String.

What Java function offsetByCodePoints really takes as an argument?

I'm trying to understand some String class functions in Java. So, here's is a simple code:
/* different experiments with String class */
public class TestStrings {
public static void main(String[] args) {
String greeting = "Hello\uD835\uDD6b";
System.out.println("Number of code units in greeting is " + greeting.length());
System.out.println("Number of code points " + greeting.codePointCount(0,greeting.length()));
int index = greeting.offsetByCodePoints(0,6);
System.out.println("index = " + index);
int cp = greeting.codePointAt(index);
System.out.println("Code point at index is " + (char) cp);
}
}
\uD835\uDD6b is an ℤ symbol, so it's ok surrogate pair.
So, the string has 6(six) code points and 7(seven) code units (2-byte chars). As it's in documentation:
offsetByCodePoints
public int offsetByCodePoints(int index,
int codePointOffset)
Returns the index within this String that is offset from the given index by codePointOffset code points.
Unpaired surrogates within the text range given by index and codePointOffset count as one code point each.
Parameters:
index - the index to be offset
codePointOffset - the offset in code points
So we do give an argument in code points. But, with given arguments (0,6) it still works fine, without exceptions. But fails for codePointAt(), because it returns 7 which is out of bounds. So, maybe the function gets its args in code units? Or I've missed something.
codePointAt takes a char index.
The index refers to char values (Unicode code units) and ranges from 0 to length() - 1.
There are six code-points in that string. The offsetByCodePoints call returns the index after 6 code-points which is char-index 7. You then try to get the codePointAt(7) which is at the end of the string.
To see why, consider what
"".offsetByCodePoints(0, 0) == 0
because to count past all 0 code-points, you have to count past all 0 chars.
Extrapolating that to your string, to count past all 6 code-points, you have to count past all 7 chars.
Maybe seeing codePointAt in use will make this clear. This is the idiomatic way to iterate over all code-points in a string (or CharSequence):
for (var charIndex = 0, nChars = s.length(), codepoint;
charIndex < nChars;
charIndex += Character.charCount(codepoint)) {
codepoint = s.codePointAt(charIndex);
// Do something with codepoint.
}
Helpful answer, Mike... For easily understanding String#offsetByCodePoints, I commented its usage and modified a bit of the question example:
I personally find the Java documentation ambiguous here.
public class TestStrings
{
public static void main(String[] args)
{
String greeting = "Hello\uD835\uDD6b";
// Gets the `char` index a.k.a. offset of the code point
// at the code point index `0` starting from the `char` index `6`¹.
// ---
// Since `6` refers to an "unpaired" low surrogate (\uDD6b), the
// returned value is 6 + 1 = 7.
//
int charIndex = greeting.offsetByCodePoints(0,6);
System.out.println("charIndex = " + charIndex);
int cp = greeting.codePointAt(charIndex);
System.out.println("Code point at index is " + (char) cp);
}
}

Categories

Resources