I have to implement a Java method, which will determine, if a input string is a hash (generated by a machine) or a plain-text (written by a human).
Example:
isThisEncrypted("qwertyuiopasdfghjklzxcvbnm"); // returns true
isThisEncrypted("some normal human text"); // returns false
I thought about using the Kolmogorov-Smirnov test (jsc.goodnessfit.KolmogorovTest), which will check, if a characters in a string are from normal distribution, but I have learned, that checking only one, short string might not be conclusive.
Do you have any idea how to solve this problem in Java (preferably using a existing library)?
From your comments:
human input can be random
this method has to determin, if string comes from this method or form
user
Then there's no way to solve your problem having just the String. You need extra information.
If you're expecting Blowfish to return a String in a given format, then you're wrong. Modern encryption algorithms target high entropy, which means they have to look and feel like random.
You have stated that you only want an approximate solution (80% accuracy), that classes of the form AClassName are likely (note capitalisation) and the given sample of encrypted text has no capitals in it. So
public class Test{
public static void main(String args[]){
String[] tests=new String[5];
tests[0]="MyClass";
tests[1]="Short";
tests[2]="thsrjtyzfgnmytkzrhjstk";
tests[3]="tatm";
tests[4]="The result is good";
for(int i=0;i<tests.length;i++){
System.out.println(tests[i]+ "- Encrypted:" + isProbablyEncrypted(tests[i]));
}
}
public static boolean isProbablyEncrypted(String in){
int noOfWords= countOccurrences(in, ' ') + countCaps(in);
if (noOfWords==0){
return true;
}else{
double averageWordLength=(double)(in.length())/(noOfWords+1);
if (averageWordLength>15){
return true;
}else{
return false;
}
}
}
public static int countOccurrences(String haystack, char needle)
{
int count = 0;
for (int i=0; i < haystack.length(); i++)
{
if (haystack.charAt(i) == needle)
{
count++;
}
}
return count;
}
public static int countCaps(String in){
int caps=0;
for (int i=0; i<in.length(); i++) {
if (Character.isUpperCase(in.charAt(i)))caps++;
}
return caps;
}
}
Is this a good solution; no, does it give >80% accuracy; yes
You split your input into words and check them against a dictionary ( checking words in a dictionary ) .
From now on everything depends on your implementation. IMO, if half the words match with the dictionary, then your method should return false.
Related
I have an exercise about the analysis of passwords (weak vs strong) and I have to create 2 constructors. One of them must receive the length of a password and the password must be created randomly, how can I do that ?
Also I'm having trouble determining if the password is weak or strong. It's going to be strong if the password has at least 3 uppercase letters, 2 lowercase letters and 6 numbers.
class Password {
private double length;
private String password;
Password()//default constructor with password length 8
{
password="defaultt";
length=8;
}
Password(double length)
{
this.length=length;
password="";//generate a random password, how?
}
boolean isStrong(String password)
{
int totalnumbers=0;
int upper=0;
int lower=0;
for(int i=0;i<password.length;i++)//marks an error in .length why?
{
if (password.charAt(i)>='0' && password.charAt(i)<='9')
totalnumbers+=1;
if (password.charAt(i) is lowercase)//what can I do here?
lower+=1;
if (password.charAt(i) is uppercase)
upper+=1;
}
if(totalnumbers>=6 && lower>=2 && upper>=3)
return true;
else
return false;
}
generatePassword(double length)
{
password;//generate the password of the object with this.length //how to do it?
}
String getPassword()
{
return password;
}
double getLength()
{
return length;
}
void setLength(double length)
{
this.length=length;
}
}
public class Exercises2 {
public static void main(String[] args) {
Password x=new Password();
Password array[];
Scanner rd=new Scanner(System.in);
int Size;
System.out.println("Give the size of the passwords array ");
Size=rd.nextInt();
array=new Password[Size];
for( int i=0;i<Size;i++)
{
array[i]=new Password();//creation of an object for each position of the array
}
for(int j=0;j<Size;j++)
{
System.out.println("Give the size for each password of the array ");
array[j]=[rd.nextInt]; //length for each password of the array
}
Password arrayBooleans[]=new Password[Size];
for (int k=0;k<Size;k++){
arrayBooleans[k]=x.isStrong(array[k]);
}
for(int i=0;i<Size;i++)
{
System.out.println("password "+i+ arrayBooleans[i]);
}
}
}
First, you shouldn't use a double for the number of characters in the password. How could you have 1.5 characters? Just use an int.
To check if a character is a digit, lower case or upper case, use the Character class (don't rely on ASCII values):
for (int i = 0; i < password.length(); i++) {
Character c = Character.valueOf(password.charAt(i));
if (c.isDigit()) {
totalnumbers++;
}
if (c.isLowerCase()) {
lower++;
}
if (c.isUpperCase()) {
upper++;
}
}
To generate a random alphanumeric string of a given length, take a look at the accepted answer for this SO post. There are many different ways to do it, but this is as good a place as any to start.
You have a few different questions here, so I'll do my best to answer them all:
Random password:
This SO question talks about random password generation, so for more details, look into what is posted there, but essentially you need to use some random generation that is built into Java and create a string out of it. There are many different ways to do it, which is detailed in that question, so I'll leave that to you to decide how you wish to do it.
Error in for loop:
Calling password.length tries to access a variable called length in the password object. In Java, you can't do that, you must use the method:
password.length()
Uppercase/lowercase detection
This SO question shows a good way to detect if a character is uppercase or lowercase based on its char value. Snippet:
if(input>='a'&&input<='z')
//lowercase
if(input>='A'&&input<='Z')
//uppercase
Try to use the simple logic,
Use Password()
{
// Simply check length
if(length == 8)
{
// Call a method which would check that password is strong or weak. for e.g,
}
}
// You can use the class java.util.Random with method to generate the password
for e.g,
char c = (char)(rnd.nextInt(128-32))+32
20x to get Bytes, which you interpret as ASCII. // If you're fine with ASCII.
// Call a method which would check that password is strong or weak.
Use the given link for random generation of password:
Creating a random string with A-Z and 0-9 in Java
http://www.baeldung.com/java-random-string
I am very new to Java and as a starter I have been offered to try this at home.
Write a program that will find out number of occurences of a smaller string in a bigger string as a part of it as well as an individual word.
For example,
Bigger string = "I AM IN AMSTERDAM", smaller string = "AM".
Output: As part of string: 3, as a part of word: 1.
While I did nail the second part (as a part of word), and even had my go at the first one (searching for the word as a part of the string), I just don't seem to figure out how to crack the first part. It keeps on displaying 1 for me with the example input, where it should be 3.
I have definitely made an error- I'll be really grateful if you could point out the error and rectify it. As a request, I am curious learner- so if possible (at your will)- please provide an explanation as to why so.
import java.util.Scanner;
public class Program {
static Scanner sc = new Scanner(System.in);
static String search,searchstring;
static int n;
void input(){
System.out.println("What do you want to do?"); System.out.println("1.
Search as part of string?");
System.out.println("2. Search as part of word?");
int n = sc.nextInt();
System.out.println("Enter the main string"); searchstring =
sc.nextLine();
sc.nextLine(); //Clear buffer
System.out.println("Enter the search string"); search = sc.nextLine();
}
static int asPartOfWord(String main,String search){
int count = 0;
char c; String w = "";
for (int i = 0; i<main.length();i++){
c = main.charAt(i);
if (!(c==' ')){
w += c;
}
else {
if (w.equals(search)){
count++;
}
w = ""; // Flush old value of w
}
}
return count;
}
static int asPartOfString(String main,String search){
int count = 0;
char c; String w = ""; //Stores the word
for (int i = 0; i<main.length();i++){
c = main.charAt(i);
if (!(c==' ')){
w += c;
}
else {
if (w.length()==search.length()){
if (w.equals(search)){
count++;
}
}
w = ""; // Replace with new value, no string
}
}
return count;
}
public static void main(String[] args){
Program a = new Program();
a.input();
switch(n){
case 1: System.out.println("Total occurences: " +
asPartOfString(searchstring,search));
case 2: System.out.println("Total occurences: " +
asPartOfWord(searchstring,search));
default: System.out.println("ERROR: No valid number entered");
}
}
}
EDIT: I will be using the loop structure.
A simpler way would be to use regular expressions (that probably defeats the idea of writing it yourself, although learning regexes is a good idea because they are very powerful: as you can see the core of my code is 4 lines long in the countMatches method).
public static void main(String... args) {
String bigger = "I AM IN AMSTERDAM";
String smaller = "AM";
System.out.println("Output: As part of string: " + countMatches(bigger, smaller) +
", as a part of word: " + countMatches(bigger, "\\b" + smaller + "\\b"));
}
private static int countMatches(String in, String regex) {
Matcher m = Pattern.compile(regex).matcher(in);
int count = 0;
while (m.find()) count++;
return count;
}
How does it work?
we create a Matcher that will find a specific pattern in your string, and then iterate to find the next match until there is none left and increment a counter
the patterns themselves: "AM" will find any occurrence of AM in the string, in any position. "\\bAM\\b" will only match whole words (\\b is a word delimiter).
That may not be what you were looking for but I thought it'd be interesting to see another approach. An technically, I am using a loop :-)
Although writing your own code with lots of loops to work things out may execute faster (debatable), it's better to use the JDK if you can, because there's less code to write, less debugging and you can focus on the high-level stuff instead of the low level implementation of character iteration and comparison.
It so happens, the tools you need to solve this already exist, and although using them requires knowledge you don't have, they are elegant to the point of being a single line of code for each method.
Here's how I would solve it:
static int asPartOfString(String main,String search){
return main.split(search, -1).length - 1;
}
static int asPartOfWord(String main,String search){
return main.split("\\b" + search + "\\b", -1).length - 1
}
See live demo of this code running with your sample input, which (probably deliberately) contains an edge case (see below).
Performance? Probably a few microseconds - fast enough. But the real benefit is there is so little code that it's completely clear what's going on, and almost nothing to get wrong or that needs debugging.
The stuff you need to know to use this solution:
regex term for "word boundary" is \b
split() takes a regex as its search term
the 2nd parameter of split() controls behaviour at the end of the string: a negative number means "retain blanks at end of split", which handle the edge case of the main string ending with the smaller string. Without the -1, a call to split would throw away the trailing blank in this edge case.
You could use Regular Expressions, try ".*<target string>.*" (Replace target string with what you are searching for.
Have a look at the Java Doc for "Patterns & Regular Expressions"
To search for the occurrences in a string this could be helpful.
Matcher matcher = Pattern.compile(".*AM.*").matcher("I AM IN AMSTERDAM")
int count = 0;
while (matcher.find()) {
count++;
}
Here's an alternative (and much shorter) way to get it to work using Pattern and Matcher,or more commonly known as regex.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CountOccurances {
public static void main(String[] args) {
String main = "I AM IN AMSTERDAM";
String search = "AM";
System.out.printf("As part of string: %d%n",
asPartOfString(main, search));
System.out.printf("As part of word: %d%n",
asPartOfWord(main, search));
}
private static int asPartOfString(String main, String search) {
Matcher m = Pattern.compile(search).matcher(main);
int count = 0;
while (m.find()) {
count++;
}
return count;
}
private static int asPartOfWord(String main, String search) {
// \b - A word boundary
return asPartOfString(main, "\\b" + search + "\\b");
}
}
Output:
As part of string: 3
As part of word: 1
For the first part of your Exercise this should work:
static int asPartOfWord(String main, String search) {
int count = 0;
while(main.length() >= search.length()) { // while String main is at least as long as String search
if (main.substring(0,search.length()).equals(search)) { // if String main from index 0 until exclusively search.length() equals the String search, count is incremented;
count++;
}
main = main.substring(1); // String main is shortened by cutting off the first character
}
return count;
You may think about the way you name variables:
static String search,searchstring;
static int n;
While search and searchstring will tell us what is meant, you should write the first word in lower case, every word that follows should be written with the first letter in upper case. This improves readability.
static int n won't give you much of a clue what it is used for if you read your code again after a few days, you might use something more meaningful here.
static String search, searchString;
static int command;
I have 2 strings "test" "bet" and another string a="tbtetse". I need to check if the "tbtetse" contains the other two strings.
I was thinking if I could find all the anagrams of string a and and then find the other two strings in those, but it doesn't work that way and also my anagram code is failing for a lengthy string.
Could you please help with any other ways to solve it?
Assuming you're trying to test whether the letters in a can be used to form an anagram of the test strings test and bet: I recommend making a dictionary (HashMap or whatever) of character counts from string a, indexed by character. Build a similar dictionary for the words you're testing. Then make sure that a has at least as many instances of each character from the test strings as they have.
Edit: Alcanzar suggests arrays of length 26 for holding the counts (one slot for each letter). Assuming you're dealing with only English letters, that is probably less of a hassle than dictionaries. If you don't know the number of allowed characters, the dictionary route is necessary.
Check below code, it may help you.
public class StringTest {
public static void main(String[] args) {
String str1 = "test";
String str2 = "bev";
String str3 = "tbtetse";
System.out.println(isStringPresent(str1, str2, str3));
}
private static boolean isStringPresent(String str1, String str2, String str3) {
if ((str1.length() + str2.length()) != str3.length()) {
return false;
} else {
String[] str1Arr = str1.split("");
String[] str2Arr = str2.split("");
for (String string : str1Arr) {
if (!str3.contains(string)) {
return false;
}
}
for (String string : str2Arr) {
if (!str3.contains(string)) {
return false;
}
}
}
return true;
}
}
basically you need to count characters in both sets and compare them
void fillInCharCounts(String word,int[] counts) {
for (int i = 0; i<word.length(); i++) {
char ch = word.charAt(i);
int index = ch - 'a';
counts[index]++;
}
}
int[] counts1 = new int[26];
int[] counts2 = new int[26];
fillInCharCounts("test",counts1);
fillInCharCounts("bet",counts1);
fillInCharCounts("tbtese",counts2);
boolean failed = false;
for (int i = 0; i<counts1.length; i++) {
if (counts1[i] > counts2[i]) {
failed = true;
}
}
if (failed) {
whatever
} else {
something else
}
If you are generalizing it, don't forget to call .toLowerCase() on the word before sending it in (or fix the counting method).
Pseudo code:
Make a copy of string "tbtetse".
Loop through each character in "test".
Do a indexOf() search for the character in your copied string and remove it if found.
If not found, fail.
Do the same for the string "bet".
class WordLetter {
char letter;
int nth; // Occurrence of that letter
...
}
One now can use Sets
Set<WordLetter>
// "test" = { t0 e0 s0 t1 }
Then testing reduces to set operations. If both words need to be present, a union can be tested. If both words must be formed from separate letters, a set of the concatenation can be tested.
/**
* #(#)palindrome1.java
*
* palindrome1 application
*
* #author
* #version 1.00 2013/11/15
*/
public class palindrome1 {
static boolean isPalindrome(String str) {
int count=0;
//check all characters of sequence is palindrome
for(int i = 0; i < str.length();i++)
{
if(str.charAt(i)!=str.charAt(str.length()-1-i))
{
return false;
}
}
//if it is return true otherwise return false
return true;
}
public static void main(String[] args) {
// TODO, add your application code
String sentence= "bob gave that pop race car to me." ;
String sentenceMax="";
String sentenceNew="";
sentence = sentence.replace( " ","");
for(int i = 0;i<sentence.length();i++)
{
for(int k=0;k<i;k++)
{
sentenceNew = sentence.substring(k,i);
if(isPalindrome(sentenceNew)&&sentenceNew.length()>sentenceMax.length());
{
sentenceMax=sentenceNew;
sentenceNew="";
}
}
}
System.out.println(sentenceMax);
}
}
The question is:t should ask a sentence from user and find the longest palindrome substring in the sentence ignoring the spaces in the sentence and print the longest palindrome substring. You MUST use the function you wrote in Part B. The sentences must be case-insensitive.
and part B is the first method named isPalindrome() in mycode.
The output should be:
racecar
but my code outputs:
e
What is wrong at my code?
You have in your code :
if(isPalindrome(sentenceNew)&&sentenceNew.length()>sentenceMax.length());
And ; is at the bad place. Since it is there it treats it as a if with an empty block, so your real block {} is calculated all the time.
It should be:
if(isPalindrome(sentenceNew)&&sentenceNew.length()>sentenceMax.length())
You are assigning a new value to sentenceMax each iteration. Try this instead
sentenceMax += sentenceNew;
Why did you not use the StringBuffer methods ?
StringBuffer.reverse() can reverse the String
after that you can search each substring in the reverted Source string using StringBuffer.indexOf(subString).
Isnt that a much simpler approach ?
As an exercise, the code block below intends to recursively go through a string and remove all the of the "x" characters. It does that, but I would like to keep track of the newStr without passing it as a parameter in the method. Is there anyway to move it into the method body?
Thanks!
public static String deathToX(String str, String newStr) {
//look for x char
if(str.substring(0, 1).equals("x")) {
//do nothing
} else {
//add non-x char to newStr
newStr += str.charAt(0);
}
if(str.length() == 1) {
return newStr;
}
return deathToX(str.substring(1), newStr);
}
public static void main(String[] args) {
System.out.println("Return: " + deathToX("xnoxmore", ""));
}
Well, you could change the code to:
public static String deathToX(String str)
{
// Termination case
if (str.length() == 0)
{
return str;
}
// Work out whether or not we want the first character
String prefix = str.startsWith("x") ? "" : str.substring(0, 1);
// Let the recursive call handle the rest of the string, and return
// the prefix (empty string or the first character) followed by the
// x-stripped remainder.
return prefix + deathToX(str.substring(1));
}
Is that the sort of thing you were thinking of?
Of course, this is a horribly inefficient way of doing string manipulation, but I assume you're more interested in the recursive nature of things.
I would like to keep track of the newStr without passing it as a parameter in the method.
Why? Passing the intermediary result into the function is often required in functional-style recursive programming. What I do is make a function that handles the bulk of the work and accepts the accumulator, and make a wrapper function that calls the previous one with the required starter value:
private static String deathToX0(String str, String newStr) {
// the original implementation
}
public static String deathToX(String str) {
return deathToX(str, "");
}
As an aside, you might not want to use a String for the intermediate result because of the copying involved. A StringBuilder would be faster.
The short answer is yes... with recursion typically on the way down the tree you work out the bit at each level in this case blank or the current character. So the return statement should call itself recursively then at the bottom of the tree the answer you wanted is reconstructed by adding together the sections at each level.
public static String deathToX(String str){
if (!str.isEmpty()){
return (str.substring(0, 1).equals("x") ? "" : str.substring(0, 1)) + deathToX(str.substring(1));
}else{
return "";
}
}
public static void main(String[] args){
System.out.println("Return: " + deathToX("xnoxmore"));
}
In the sample above I used the shorthand if format to put it all on one line but you could expand it out. You should be able to see that the recursive function recurses on the return statement and I put in a special case for the last level. If you were to split it and put this levels answer in a local variable e.g. tmp then you would use:
return tmp + deathToX(str.substring(1));
Remember recursion means that the current execution is only paused until the lower ones finish so you can happily store info to recover on your way back up. Hope this helps :)
public class solution {
// Return the changed string
public static String removeX(String input){
if(input.equals("") || input.equals("x"))
return "";
String returnStr="";
removeX(input.substring(1));
for(int i=0;i<input.length();i++)
{
if(input.charAt(i)=='x')
continue;
else
returnStr+=input.charAt(i);
}
return returnStr;
}
}
This is my approach. This code goes to the end of the string, if it gets X as last string, it returns ""(nothing), then it checks the whole substring for "x", if its present in the string, it will continue, else it will append rest character to that string and it goes on.
Finally returns the updated string.!
Hope this helps..!! well, this is my first contribution here :)