Java Comparing characters in strings and counting the similarities - java

my question is asking this:
Write a program that compares two input strings. Output the number of characters that match in each string position. The output should use the correct verb (match vs matches) according to the character count.
Ex: If the input is:
crush crash
the output is:
4 characters match
this is what i have so far:
import java.util.Scanner;
public class LabProgram
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
String str1 = in.next();
String str2 = in.next();
int counter=0;
if(str1.indexof(0)==str2.indexof(0)){
counter++;
System.out.println(counter+"character match");
else
System.out.println("All characters match");
}
}
I know it doesn't look like a lot but I've tried this so many other ways but I clearly am missing something that would make this easier to do. I wanted to count the similar letters in my counter...but I don't know what to do.

Use a for loop to iterate across the string inputs and utilize charAt() to look at specific characters within a string
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String str1 = in.next();
String str2 = in.next();
int counter=0;
// Loop across the smaller input string
// Math.min gives us the lesser of 2 values
for (int i = 0; i < Math.min(str1.length(), str2.length()); i++){
// If two characters match
if (str1.charAt(i) == str2.charAt(i)){
// Increment counter
counter++;
}
}
// If counter = length of both strings
if (counter == str1.length() && counter == str2.length()){
System.out.println("All characters match");
// If counter is 1
} else if (counter == 1){
System.out.println("1 character matches");
// Otherwise
} else {
System.out.println(counter + " characters match");
}
}
Note: To use Math.Min(), you'll need to
import java.lang.Math;
It's not completely necessary though; you could just figure out which string is longer on your own

Code point
Avoid using char. That type is essentially broken since Java 2, legacy since Java 5. As a 16-bit value, char is physically incapable of representing most characters. One emoji could ruin your whole day.
Instead, use code point integer numbers when working with individual characters. You’ll find code point related methods on several classes, including String, StringBuilder, and Character.
int[] codePointsX = x.codePoints().toArray() ;
int[] codePointsY = y.codePoints().toArray() ;
First, check lengths.
boolean sameLength = ( codePointsX.length == codePointsY.length ) ;
if ( ! sameLength ) { … }
Create an array to hold results of comparing each character.
int[] results = new int[ codePointsX.length ] ;
Compare. The ternary operator ?: is a condensed alternative to using an if test.
We put a zero into results array if the two code points match. Else, we put a zero into results array. The default is a zero, so we could skip the assignment of zero. But I want our intentions to be crystal clear to the reader.
for( int index = 0 ; index < codePointsX.length ; index ++ )
{
results[ index ] =
codePointsX[ index ] == codePointsY[ index ] ? 1 : 0 ; // One for a matching character, Zero for a mismatch.
}
Results.
int countMatches = Arrays.stream( results ).sum();
Full example code.
String x = "cat" ;
String y = "cot" ;
int[] codePointsX = x.codePoints().toArray() ;
int[] codePointsY = y.codePoints().toArray() ;
boolean sameLength = ( codePointsX.length == codePointsY.length ) ;
if ( ! sameLength ) {
throw new IllegalArgumentException( "The two input strings have different lengths. " ) ;
}
int[] results = new int[ codePointsX.length ] ;
for( int index = 0 ; index < codePointsX.length ; index ++ )
{
results[ index ] =
codePointsX[ index ] == codePointsY[ index ] ? 1 : 0 ;
}
int countMatches = Arrays.stream( results ).sum();
System.out.println( Arrays.toString( results ) ) ;
System.out.println( "countMatches = " + countMatches ) ;
See this code run at Ideone.com.
[1, 0, 1]
countMatches = 2

Related

How to delete every 12th character from a string in java

Lets say I have a string like this:
String str = "~asdfl;kjx,~rgadfaeg,dsafnewgfljka;ldfjsfa;dlkjfa;lvjvbnaber;fwelfjadfafa"
int character = 12
What I want to do is delete every 12th character in the string, so i would delete the 12 index, then the 24th, then the 36th, etc until the string is over.
Which index I delete (every 12th, or every 2nd) has to equal the character variable I have, since that variable changes.
I tried doing this with regex:
System.out.println(s.replaceAll(".(.)", "$12"));
But it didnt work. any help?
Sometimes, a simple for loop is all you need:
public class Test {
public static void main(String[] args) {
String str = "~asdfl;kjx,~rgadfaeg,dsafnewgfljka;ldfjsfa;dlkjfa;lvjvbnaber;fwelfjadfafa";
int character = 12;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
if ((i + 1) % character != 0) {
sb.append(str.charAt(i));
}
}
String result = sb.toString();
System.out.println(result);
}
}
If you insist on using regular expressions, you can interpolate the character variable into the expression as follows:
public class Test {
public static void main(String[] args) {
String str = "~asdfl;kjx,~rgadfaeg,dsafnewgfljka;ldfjsfa;dlkjfa;lvjvbnaber;fwelfjadfafa";
int character = 12;
System.out.println(str.replaceAll("(.{" + (character - 1) + "}).", "$1"));
}
}
To delete every 12th character using regex, use this pattern:
(.{11}).
And then replace with just the captured $1.
Sample Java code:
String str = "~asdfl;kjx,~rgadfaeg,dsafnewgfljka;ldfjsfa;dlkjfa;lvjvbnaber;fwelfjadfafa";
String output = str.replaceAll("(.{11}).", "$1");
System.out.println(output);
This prints:
~asdfl;kjx,rgadfaeg,dsfnewgfljka;dfjsfa;dlkja;lvjvbnabe;fwelfjadfaa
Edit:
To do a regex replacement of some fixed width, use:
String str = "~asdfl;kjx,~rgadfaeg,dsafnewgfljka;ldfjsfa;dlkjfa;lvjvbnaber;fwelfjadfafa";
int width = 11;
String output = str.replaceAll("(.{" + width + "}).", "$1");
System.out.println(output);
Avoid char
The char type in Java is legacy, essentially broken. As a 16-bit value, a char is incapable of representing most characters.
Code points
Instead, use code point integers.
Make an array of each character’s code point.
int[] codePointsArray = input.codePoints().toArray() ;
Make a list of that array.
List< Integer > codePoints = List.of( codePointsArray ) ;
Alternatively:
List< Integer > codePoints = input.codePoints().boxed().toList() ;
Make an IntStream of the indexes we need to access each element of that list. Use each index to pull out a code point, and filter by the nth element. Collect into a StringBuilder.
String result =
IntStream
.range( 0 , codePoints.size() )
.filter( n -> n % 12 != 0 )
.mapToObj( codePoints :: get )
.collect( StringBuilder :: new , StringBuilder :: appendCodePoint , StringBuilder :: append )
.toString()
;
That is untested code, but should be close to what you need.
My code here is based on what I saw on this similar Question.

Count the numbers of numeric value in a given string

Java program to accept a string and count total numeric values.
public class Test2{
public static void main(String[] args){
String str = "I was 2 years old in 2002";
int count = 0, i;
for(i = 0; i < str.length(); i++){
if(str.charAt(i) >= 48 && str.charAt(i) <= 57){
count++;
// while(str.charAt(i) >= 48 && str.charAt(i) <= 57)
// i++;
}
}
System.out.println("Output: " +count);
}
}
Output = 5
After uncommenting the two lines written inside while loop -
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 25
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
at java.base/java.lang.String.charAt(String.java:712)
at Test2.main(Test2.java:9)
The output should be 2, because there are two numeric values - 2 and 2002
I have commented on the two lines in the above code, after uncommenting the code, the same logic works perfectly in C++.
An alternative to #DarkMatter´s answer using Pattern:
public static void main(String[] args) {
String str = "I was 2 years old in 2002";
long count = Pattern.compile("\\d+").matcher(str).results().count();
System.out.println(count);
}
You are checking individual charters so it counts every digit (as you probably realize). Java String has some nice tools to help you here. You could split the line into words and check each against a regular expression using String.matches():
String str = "I was 2 years old in 2002";
int count = 0;
for(String s : str.split(" ")) {
if(s.matches("[0-9]*")) {
count++;
}
}
System.out.println(count);
You can do the same thing (almost) with a stream:
String str = "I was 2 years old in 2002";
long count = Arrays.stream(str.split(" "))
.filter(s -> s.matches("[0-9]*")).count();
System.out.println(count);
In C, strings end in an ASCII NUL character (well, in basic C, strings don't exist, it's a library bolt-on, but most bolt-ons have NUL terminated strings). In java, that's not how it works.
The reason that your code is not working in java, but it is in C, is that you just keep going until you hit a non-digit character in that inner while loop. That means if the string ends in a digit (which yours does), your code asks the string: Give me the character at (one position beyond its length). In C that works; that's ASCII NUL, and thus your inner loop ends, as that's not a digit.
In java it doesn't, because you can't ask for a character beyond the end of a string.
You can 'fix' your code as pasted by also adding a check that i is still below length: if (i < str.length() && str.charAt(i).... ).
As the other answers showed you, there are more java idiomatic ways to solve this problem too, and probably the strategies shown in the other answers is what your average java coder would most likely do if faced with this problem. But there's nothing particularly wrong with your C-esque solution, once you add the 'check length' fix.
below code will input String from user and return the number of occurrences of numeric values as count.
import java.util.Scanner;
public class NumberCountingString
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
String str = in.nextLine();
int count = 0, i;
int size = str.length(); // will only get size once instead of using in loop which will always get size before comparing
for(i = 0; i < size; i++)
{
if(Character.isDigit(str.charAt(i))) //if char is digit count++
{
count++;
for (int j = i; j < size; ) //inner loop to check if next characters are also digits
{
if(Character.isDigit(str.charAt(j))) // if yes skip next char
{
i++;
j=i;
}
else{ //break inner loop
break;
}
}
}
}
System.out.println("Output: " +count);
}
}
There are many options in Java as already shared by others. Below is very similar to your existing code and gives your desired output:
public static void main(String[] args) {
String str = "I was 2 years old in 2002";
String[] splittedString = str.split(" ");
int count = 0, i;
for (i = 0; i < splittedString.length; i++) {
if (StringUtils.isNumeric(splittedString[i])) {
count++;
}
}
System.out.println("Output: " + count);
}
You can split this string into an array of words, then filter those words where codePoints of the characters match digits, i. e. allMatch (Character::isDigit), and count these words:
String str = "I was 2 years old in 2002";
long count = Arrays
// split string into an array of words
.stream(str.split("\\s+"))
// for each word check the code points of the
// characters, whether they are digits or not.
.filter(w -> w.codePoints()
.mapToObj(ch -> (char) ch)
.allMatch(Character::isDigit))
.count();
System.out.println(count); // 2
See also: Transform String to byte then to int

Accessing index values before and after symbol from input

I am trying to take the input and if there is an # symbol in the input then it finds the maximum of the integers before and after the # symbol. The maximum part I have no problem with but I do not know how to access and find the values before and after the # symbol.
import java.util.Scanner;
public class Max_Min {
public static void main(String[] args) {
//gets keyboard
Scanner keyboard = new Scanner(System.in);
//puts input into string
String inputString = keyboard.nextLine();
//splits string between characters
String[] splitInput = inputString.split("");
for (String s : splitInput) {
if(s.equals("#")){
//computes the maximum of the two integers before and after the #
}
}
//close keyboard
keyboard.close();
I did do a search to find something simliar (and im sure there is something) but could not find anything. If someone could help that would be great!
Try with this:
for (int i = 0; i < splitInput.length; i++){
if (splitInput[i].equals("#") && i != 0 && i != splitInput.length -1){
int max = Math.max(Integer.parseInt(splitInput[i - 1]), Integer.parseInt(splitInput[i + 1]));
}
//...
}
You could try:
String[] splitInput = inputString.split("#");
which would split your string at the #s.
Then you can do a iteration over your splitInput array and do a .length on each index.
You have written the simple for loop, with which you can only access the string, but not its index in the array. If you had the index, you could write:
int possibleMax = Integer.parseInt(splitInput[i - 1]) + Integer.parseInt(splitInput[i + 1]);
To get the index, there are two ways:
for (int i = 0; i < splitInput.length; i++) {
String s = splitInput[i];
...
}
Or:
int i = 0;
for (String s : splitInput) {
…
i++;
}
I don't like either version because both are more complicated than absolutely necessary, in terms of written code. If you would use Kotlin instead of Java, it would be:
splitInput.forEachIndexed { i, s ->
…
}
In Java this could be written:
forEachIndexed(
splitInput,
(i, s) -> …
);
The problem in Java is that the code inside the … cannot update the variables of the enclosing method. I'm not sure whether this will ever change. It would be possible but needs a lot of work by the language committee.
A simple way to do this would be
String input = "12#23";
String [] arr = input.split("#");
if (arr.length == 2) {
System.out.println("Max is "+Math.max(Integer.valueOf(arr[0]),Integer.valueOf(arr[1])));
}

How to separate many different words from a string (Java)

I've been struggling to figure out how to get a word, of unknown length, from a string, of unknown length, that I'm reading from a file. The words I want from the string are always separated by "." and/or "&" with the whole string being surrounded by quotes. EX: ".Word.Characters&Numeric&Letters.Typos&Mistypes." I know the location of each "." and "&" as well as how many times they occur.
I want to feed the words into an array Example[i][j] based on whether or not the words are separated by a "." or a "&". So words contained between "." would be set into the i column of the array and words linked by "&" into the j rows of the array.
The input string can contain a largely variable number of words. Meaning that there can be only one word of interest, or one hundred+.
I'd prefer to use arrays to solve this problem. From what I've read regex would be slow, but work. split() may also work, but I think I'd have to know what words to look for before hand.
From this String: ".Word.Characters&Numeric&Letters.Typos&Mistypes." I'd expect to get: (without worrying about which is a row or column)
[[Word],[null],[null]],
[[Characters],[Numbers],[Letters]],
[[Typos],[Mistypes],[null]]
From this String ".Alpha.Beta.Zeta&Iota." I'd expect to get:
[[Alpha],[null]],
[[Beta],[null]],
[[Zeta],[Iota]]
//NumerOfPeriods tells me how many word "sections" are in the string
//Stor[] is an array that holds the string index locations of "."
for(int i=0;i<NumberOfPeriods;i++)
{
int length = Stor[i];
while(Line.charAt(length) != '"')
{
length++;
}
Example[i] = Line.substring(Stor[i], length);
}
//This code can get the words separated by "." but not by "&"
//Stor[] is an array that holds all string index locations of '.'
//AmpStor[] is an array that holds all string index locations of '&'
int TotalLength = Stor[0];
int InnerLength = 0;
int OuterLength = 0;
while(Line.charAt(TotalLength) != '"')
{
while(Line.charAt(OuterLength)!='.')
{
while(Line.charAt(InnerLength)!='&')
{
InnerLength++;
}
if(Stor[i] > AmpStor[i])
{
Example[i][j] = Line.substring(Stor[i], InnerLength);
}
if(Stor[i] < AmpStor[i])
{
Example[i][j] = Line.substring(AmpStor[i],InnerLength);
}
OuterLength++;
}
}
//Here I run into the issue of indexing into different parts of the array i & j
This is how I would solve your problem (it's completely different from your code but it works).
First of all, remove the quotes and the leading and trailing non-word characters. This can be done using replaceAll:
String Formatted = Line.replaceAll( "(^\"[.&]*)|([.&]*\"$)", "" );
The regular expression in the first argument will match the double quotes at both ends and the leading and trailing .s and &s. The method will return a new string where the matched characters are removed, because the second argument is an empty string (it replaces with an empty string).
Now you can split this string at each . using the split method. You could only define your output array after this call:
String[] StringGroups = Formatted.split( "\\." );
String[][] Elements = new String[StringGroups.length][];
Use an escaped backslash (\\) before the point to indicate that it should split on .-characters, since this method takes in a regular expression (and just . splits on any non-newline character).
Now split each string in that array at each & using the same split method. Add the result directly to your Elements array:
// Loop over the array
int MaxLength = 0;
for( int i = 0; i < StringGroups.length; i ++ ) {
String StrGroup = StringGroups[ i ];
String[] Group = StrGroup.split( "&" );
Elements[ i ] = Group;
// Measure the max length
if( Group.length > MaxLength ) {
MaxLength = Group.length;
}
}
A \\ is not necessary for the input, since & just matches &-characters. Now you only have to fill in your data into an array. The MaxLength variable is for adding the null values to your array. If you don't want them, just remove them and you're done here.
If you want the null values however, loop over your elements array and copy the current rows into new arrays:
for( int i = 0; i < Elements.length; i ++ ) {
String[] Current = Elements[ i ];
String[] New = new String[ MaxLength ];
// Copy existing values into new array, extra values remain null
System.arraycopy( Current, 0, New, 0, Current.length );
Elements[ i ] = New;
}
Now, the Elements array contains exactly what you wanted.
Here is the complete executable code:
public class StringSplitterExample {
public static void main( String[] args ) {
test( "\".Word.Characters&Numeric&Letters.Typos&Mistypes.\"" );
System.out.println(); // Line between
test( "\".Alpha.Beta.Zeta&Iota.\"" );
}
public static void test( String Line ) {
String Formatted = Line.replaceAll( "(^\"[.&]*)|([.&]*\"$)", "" );
String[] StringGroups = Formatted.split( "\\." );
String[][] Elements = new String[StringGroups.length][];
// Loop over the array
int MaxLength = 0;
for( int i = 0; i < StringGroups.length; i ++ ) {
String StrGroup = StringGroups[ i ];
String[] Group = StrGroup.split( "&" );
Elements[ i ] = Group;
// Measure the max length
if( Group.length > MaxLength ) {
MaxLength = Group.length;
}
}
for( int i = 0; i < Elements.length; i ++ ) {
String[] Current = Elements[ i ];
String[] New = new String[ MaxLength ];
// Copy existing values into new array, extra values remain null
System.arraycopy( Current, 0, New, 0, Current.length );
Elements[ i ] = New;
}
for( String[] Group : Elements ) {
for( String String : Group ) {
System.out.print( String );
System.out.print( " " );
}
System.out.println();
}
}
}
The output of this example:
Word null null
Characters Numeric Letters
Typos Mistypes null
Alpha null
Beta null
Zeta Iota
So this works, and you don't even need to know where the . and & characters are in your string. Java will just do that for you.
If I understand the problem correctly, you want to separate the string into substrings delimited by '.' and then for each of the substrings, separate it into subsubstrings delimited by '&'. If that's the case, then I would use the split method:
List<List<String>> terms = Arrays.stream(input.split("\\."))
.map(s -> Arrays.asList(s.split("\\&"))
.collect(Collectors.toList());
if you really need it to be returned as a null-padded array:
String[][] result = new String[terms.size()][ terms.stream.mapToInt(List::size).max().getAsInt()];
IntStream.range(0, terms.size()).forEach(i ->
IntStream.range(0, terms.get(i).size()).forEach(j ->
result[i][j] = terms.get(i).get(j)));
Here is how I tried to solve the problem:
import java.util.*;
import java.util.stream.*;
public class StringSplitSplits {
private static final String S1 = ".Word.Characters&Numeric&Letters.Typos&Mistypes.";
private static final String S2 = ".Alpha.Beta.Zeta&Iota.";
public static void main(String [] args) {
String str = stripStartAndEndDots(S1);
String [] ss = str.split("\\.");
int maxLength = getMaxLength(ss);
String [][] sss = Stream.of(ss)
.map(s -> s.split("&"))
.map(s -> Arrays.copyOf(s, maxLength))
.toArray(String[][]::new);
Stream.of(sss).forEach(s -> System.out.println(Arrays.toString(s)));
}
private static String stripStartAndEndDots(String input) {
if (input.startsWith(".")) {
input = input.substring(1);
}
if (input.endsWith(".")) {
input = input.substring(0, input.length()-1);
}
return input;
}
/*
* Get max length of the arrays split on the "&" for each
* string element of the input string array.
*/
private static int getMaxLength(String [] input) {
return Stream.of(input)
.map(s -> s.split("&"))
.mapToInt(ss -> ss.length)
.max()
.orElse(0);
}
}
Input: ".Word.Characters&Numeric&Letters.Typos&Mistypes."
Output:
[Word, null, null]
[Characters, Numeric, Letters]
[Typos, Mistypes, null]
Input: ".Alpha.Beta.Zeta&Iota."
Output:
[Alpha, null]
[Beta, null]
[Zeta, Iota]

breaking down any String

Hi guys I am busy with breaking / splitting Strings.
However the String is not fixed so when the input changes the program still has to work with any character input.
Till now I got this far but I got lost.
I have made an array of characters and set the size of the array equal to the lenght of any string that is will get as input. I made a for loop to loop through the characters of a string.
how do I insert my string now into the array because I know that my string is not yet in there? Then when its finally looping through the characters of my string is has to printout numbers and operands on different lines. So the ouput would look like in this case like this;
1
+
3
,
432
.
123
etc
I want to do this without using matchers,scanner, etc. I want to use basic Java techniques like you learn in the first 3 chapters of HeadfirstJava.
public class CharAtExample {
public static void main(String[] args) {
// This is the string we are going to break down
String inputString = "1+3,432.123*4535-24.4";
int stringLength = inputString.length();
char[] destArray = new char[stringLength];{
for (int i=0; i<stringLength; i++);
}
You could use Character.isDigit(char) to distinguish numeric and not numeric chars as actually this is the single criteria to group multiple chars in a same line.
It would give :
public static void main(String[] args) {
String inputString = "1+3,432.123*4535-24.4";
String currentSequence = "";
for (int i = 0; i < inputString.length(); i++) {
char currentChar = inputString.charAt(i);
if (Character.isDigit(currentChar)) {
currentSequence += currentChar;
continue;
}
System.out.println(currentSequence);
System.out.println(currentChar);
currentSequence = "";
}
// print the current sequence that is a number if not printed yet
if (!currentSequence.equals("")) {
System.out.println(currentSequence);
}
}
Character.isDigit() relies on unicode category.
You could code it yourself such as :
if (Character.getType(currentChar) == Character.DECIMAL_DIGIT_NUMBER) {...}
Or you could code it still at a lower level by checking that the int value of the char is included in the range of ASCII decimal values for numbers:
if(currentChar >= 48 && currentChar <= 57 ) {
It outputs what you want :
1
+
3
,
432
.
123
*
4535
-
24
.
4
It's easier than you might think.
First: to get an array with the chars of your string you just use the toCharArray() method that all strings have. ex. myString.toCharArray()
Second: When you see that a character is not a number, you want to move to the next line, print the character and then move to the next line again. The following code does exactly that :
public class JavaApplication255 {
public static void main(String[] args) {
String inputString = "1+3,432.123*4535-24.4";
char[] destArray = inputString.toCharArray();
for (int i = 0 ; i < destArray.length ; i++){
char c = destArray[i];
if (isBreakCharacter(c)){
System.out.println("\n" + c);
} else {
System.out.print(c);
}
}
}
public static boolean isBreakCharacter(char c){
return c == '+' || c == '*' || c == '-' || c == '.' || c == ',' ;
}
char[] charArray = inputString.toCharArray();
Here is a possible solution where we go character by character and either add to an existing string which will be our numbers or it adds the string to the array, clears the current number and then adds the special characters. Finally we loop through the array as many times as we find a number or non-number character. I used the ASCII table to identify a character as a digit, the table will come in handy throughout your programming career. Lastly I changed the array to a String array because a character can't hold a number like "432", only '4' or '3' or '2'.
String inputString = "1+3,432.123*4535-24.4";
int stringLength = inputString.length();
String[] destArray = new String[stringLength];
int destArrayCount = 0;
String currentString = "";
for (int i=0; i<stringLength; i++)
{
//check it's ascii value if its between 0 (48) and 9 (57)
if(inputString.charAt(i) >= 48 && inputString.charAt(i) <= 57 )
{
currentString += inputString.charAt(i);
}
else
{
destArray[destArrayCount++] = currentString;
currentString = "";
//we know we don't have a number at i so its a non-number character, add it
destArray[destArrayCount++] = "" + inputString.charAt(i);
}
}
//add the last remaining number
destArray[destArrayCount++] = currentString;
for(int i = 0; i < destArrayCount; i++)
{
System.out.println("(" + i + "): " + destArray[i]);
}
IMPORTANT - This algorithm will fail if a certain type of String is used. Can you find a String where this algorithm fails? What can you do to to ensure the count is always correct and not sometimes 1 greater than the actual count?

Categories