I have a word on which I need to replace a certain character with an asterisk, but I need to get all the replaced variations from this word. For eg. I want to replace character 'e' with an asterisk in:
String word = telephone;
but to get this list as a result:
List of words = [t*lephone, tel*phone, telephon*, t*l*phone, t*lephon*, tel*phon*, t*l*phon*];
Is there a quick way to do this in Java?
The following code will do that in a recursive way:
public static Set<String> getPermutations(final String string, final char c) {
final Set<String> permutations = new HashSet<>();
final int indexofChar = string.indexOf(c);
if (indexofChar <= 0) {
permutations.add(string);
} else {
final String firstPart = string.substring(0, indexofChar + 1);
final String firstPartReplaced = firstPart.replace(c, '*');
final String lastPart = string.substring(indexofChar + 1, string.length());
for (final String lastPartPerm : getPermutations(lastPart, c)) {
permutations.add(firstPart + lastPartPerm);
permutations.add(firstPartReplaced + lastPartPerm);
}
}
return permutations;
}
It adds the original String to the output, so:
public static void main(String[] args) {
String word = "telephone";
System.out.println(getPermutations(word, 'e'));
}
Outputs:
[telephone, t*lephone, tel*phone, t*l*phone, telephon*, t*lephon*, tel*phon*, t*l*phon*]
But you can always call remove on the returned Set with the original word.
Related
I want to find how many words there are in a string but ignore the similar words in it.
For example the main method should return 8 insetad of 9.
I want it to be a method which takes one parameter s of type String and returns an int value. And im only allowed to use the bacics,so no HashMaps, ArrayLists, only charAt, length, or substring and using loops and if statemens are allowed.
public static void main(String[] args) {
countUniqueWords("A long long time ago, I can still remember");
public static int countUniqueWords(String str) {
char[] sentence = str.toCharArray();
boolean inWord = false;
int wordCt = 0;
for (char c : sentence) {
if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') {
if (!inWord) {
wordCt++;
inWord = true;
}
} else {
inWord = false;
}
}
return wordCt;
}
```
Don't force yourself to limited options, and learn the Streaming API. Your question is as simple as:
public static long countUniqueWords(String str) {
var str2 = str.replaceAll("[^a-zA-Z0-9 ]", "").replaceAll(" +", " ");
return Arrays.stream(str2.split(" "))
.distinct()
.count();
}
[Optional step] Get get rid of all non alphanumeric chars
Split the string per empty slot
Remove duplicates
Add them together
To ignore same words in a string, you can use a combination of the split and distinct methods from the Java Stream API.
// Define the input string
String input = "This is a test string with some repeating words";
// Split the string into an array of words
String[] words = input.split("\\s+");
// Use the distinct method to remove duplicate words from the array
String[] distinctWords = Arrays.stream(words).distinct().toArray(String[]::new);
// Print the distinct words
System.out.println(Arrays.toString(distinctWords));
Try this:
public static int countUniqueWords(String words) {
// Add all the words to a list
List<String> array = new ArrayList<>();
Scanner in = new Scanner(words);
while (in.hasNext()) {
String s = in.next();
array.add(s);
}
// Save per word the amount of duplicates
HashMap<String, Integer> listOfWords = new HashMap<>();
Iterator<String> itr = array.iterator();
while (itr.hasNext()) {
String next = itr.next();
String prev = listOfWords.getOrDefault(next, 0);
listOfWords.put(next, prev + 1);
}
// Grab the size of all known words
return listOfWords.size();
}
public static void main(String args[]) {
int count = countUniqueWords("A long long time ago, I can still remember");
System.out.println("The number of unique words: " + count);
}
This post is an update to this one : get specific character in a string with regex and remove unused zero
In the first place, i wanted to remove with an regular expression the unused zero in the last match.
I found that the regular expression is a bit overkill for what i need.
Here is what i would like now,
I would like to use split() method
to get from this :
String myString = "2020-LI50532-3329-00100"
this :
String data1 = "2020"
String data2 = "LI50532"
String data3 = "3329"
String data4 = "00100"
So then i can remove from the LAST data the unused Zero
to convert "00100" in "100"
And then concatenate all the data to get this
"2020-LI50532-3329-100"
Im not familiar with the split method, if anyone can enlight me about this ^^
You can use substring method to get rid of the leading zeros...
String myString = "2020-LI50532-3329-00100";
String[] data = myString.split("-");
data[3] = data[3].substring(2);
StringBuilder sb = new StringBuilder();
sb.append(data[0] + "-" + data[1] + "-" + data[2] + "-" + data[3]);
String result = sb.toString();
System.out.println(result);
Assuming that we want to remove the leading zeroes of ONLY the last block, maybe we can:
Extract the last block
Convert it to Integer and back to String to remove leading zeroes
Replace the last block with the String obtained in above step
Something like this:
public String removeLeadingZeroesFromLastBlock(String text) {
int indexOfLastDelimiter = text.lastIndexOf('-');
if (indexOfLastDelimiter >= 0) {
String lastBlock = text.substring(indexOfLastDelimiter + 1);
String lastBlockWithoutLeadingZeroes = String.valueOf(Integer.valueOf(lastBlock)); // will throw exception if last block is not an int
return text.substring(0, indexOfLastDelimiter + 1).concat(lastBlockWithoutLeadingZeroes);
}
return text;
}
Solution using regex:
public class Main {
public static void main(String[] args) {
// Test
System.out.println(parse("2020-LI50532-3329-00100"));
System.out.println(parse("2020-LI50532-3329-00001"));
System.out.println(parse("2020-LI50532-03329-00100"));
System.out.println(parse("2020-LI50532-03329-00001"));
}
static String parse(String str) {
return str.replaceAll("0+(?=[1-9]\\d*$)", "");
}
}
Output:
2020-LI50532-3329-100
2020-LI50532-3329-1
2020-LI50532-03329-100
2020-LI50532-03329-1
Explanation of the regex:
One or more zeros followed by a non-zero digit which can be optionally followed by any digit(s) until the end of the string (specified by $).
Solution without using regex:
You can do it also by using Integer.parseInt which can parse a string like 00100 into 100.
public class Main {
public static void main(String[] args) {
// Test
System.out.println(parse("2020-LI50532-3329-00100"));
System.out.println(parse("2020-LI50532-3329-00001"));
System.out.println(parse("2020-LI50532-03329-00100"));
System.out.println(parse("2020-LI50532-03329-00001"));
}
static String parse(String str) {
String[] parts = str.split("-");
try {
parts[parts.length - 1] = String.valueOf(Integer.parseInt(parts[parts.length - 1]));
} catch (NumberFormatException e) {
// Do nothing
}
return String.join("-", parts);
}
}
Output:
2020-LI50532-3329-100
2020-LI50532-3329-1
2020-LI50532-03329-100
2020-LI50532-03329-1
you can convert the last string portion to integer type like below for removing unused zeros:
String myString = "2020-LI50532-3329-00100";
String[] data = myString.split("-");
data[3] = data[3].substring(2);
StringBuilder sb = new StringBuilder();
sb.append(data[0] + "-" + data[1] + "-" + data[2] + "-" + Integer.parseInt(data[3]));
String result = sb.toString();
System.out.println(result);
You should avoid String manipulation where possible and rely on existing types in the Java language. One such type is the Integer. It looks like your code consists of 4 parts - Year (Integer) - String - Integer - Integer.
So to properly validate it I would use the following code:
Scanner scan = new Scanner("2020-LI50532-3329-00100");
scan.useDelimiter("-");
Integer firstPart = scan.nextInt();
String secondPart = scan.next();
Integer thirdPart = scan.nextInt();
Integer fourthPart = scan.nextInt();
Or alternatively something like:
String str = "00100";
int num = Integer.parseInt(str);
System.out.println(num);
If you want to reconstruct your original value, you should probably use a NumberFormat to add the missing 0s.
The main points are:
Always try to reuse existing code and tools available in your language
Always try to use available types (LocalDate, Integer, Long)
Create your own types (classes) and use the expressiveness of the Object Oriented language
public class Test {
public static void main(String[] args) {
System.out.println(trimLeadingZeroesFromLastPart("2020-LI50532-03329-00100"));
}
private static String trimLeadingZeroesFromLastPart(String input) {
String delem = "-";
String result = "";
if (input != null && !input.isEmpty()) {
String[] data = input.split(delem);
StringBuilder tempStrBldr = new StringBuilder();
for (int idx = 0; idx < data.length; idx++) {
if (idx == data.length - 1) {
tempStrBldr.append(trimLeadingZeroes(data[idx]));
} else {
tempStrBldr.append(data[idx]);
}
tempStrBldr.append(delem);
}
result = tempStrBldr.substring(0, tempStrBldr.length() - 1);
}
return result;
}
private static String trimLeadingZeroes(String input) {
int idx;
for (idx = 0; idx < input.length() - 1; idx++) {
if (input.charAt(idx) != '0') {
break;
}
}
return input.substring(idx);
}
}
Output:
2020-LI50532-3329-100
How to check if some String contains a specific String like "ABC72961". So we search for String which starts with "ABC" following by 5 digits. I've implemented a algorithm but I want it with "matches" or somehow else and then check the speed of these two solutions.
You may want to use regex for this
^ABC[0-9]{5}$
^ : Beginning of the string
ABC : Matches ABC literally (case-sensitive)
[0-9]{5} : Matches 5x numbers from 0 to 9
$ : End of the string
And use String#matches to test it
Regex101
Example
String regex = "^ABC[0-9]{5}$";
String one = "ABC72961";
String two = "ABC2345";
String three = "AB12345";
String four = "ABABABAB";
System.out.println(one.matches(regex)); // true
System.out.println(two.matches(regex)); // false
System.out.println(three.matches(regex)); // false
System.out.println(four.matches(regex)); // false
EDIT
Seeing your comment, you want it to work for String one = "textABC72961text" also. For that to be possible, you should just erase ^ and $ that limit the String.
.*ABC[0-9]{5}.*
EDIT 2
Here is if you want to extract it
if (s.matches(".*ABC[0-9]{5}.*")) {
Matcher m = Pattern.compile("ABC[0-9]{5}").matcher(s);
m.find();
result = m.group();
}
str.contains("ABC72961");
Returns true if str contains the string. False if not.
public String getString() {
String str = extractString();
return str;
}
public boolean exists() {
return !getString().trim().equals("") ? false : true;
}
private List<Integer> getPositionsOfABC() {
List<Integer> positions = new ArrayList<>();
int index = text.indexOf("ABC");
while (index > 0) {
positions.add(index);
index = text.indexOf("ABC", index + 1);
}
return positions;
}
private static boolean isInteger(String str) {
boolean isValidInteger = false;
try {
Integer.parseInteger(str);
isValidInteger = true;
} catch (NumberFormatException ex) {
return isValidInteger;
}
return isValidInteger;
}
private String extractString() {
List<Integer> positions = getPositionsOfABC();
for (Integer position : positions) {
int index = position.intValue();
String substring = text.substring(index, index + LENGTH_OF_DIGITS);
String lastDigits = substring.substring(3, substring.length());
if (isInteger(lastDigits)) {
return substring;
}
}
return "";
}
Here's a simple code that checks whether a substring exists in a string without using library functions, regex or other complex data structures.
class SSC {
public static void main(String[] args) {
String main_str <-- MAIN STRING
String sub_str <-- SUBSTRING
String w; int flag=0;
for(int i=0;i<=main_str.length()-sub_str.length();i++){
w="";
for(int j=0;j<sub_str.length();j++){
w+=main_str.charAt(i+j);
}
if(w.equals(sub_str))
flag++;
}
if(flag>0)
System.out.print("exists "+flag+" times");
else
System.out.print("doesn't exist");
}
}
Hope this helps.
I think what you want to use is java.util.regex.Pattern.
Pattern p = Pattern.compile("ABC(\d*)");
Matcher m = p.matcher("ABC72961");
boolean b = m.matches();
or if it shall be exactly 5 digits after "ABC", you can use the regex ABC(\d{5})
https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#compile(java.lang.String)
Another solution would be:
String stringToTest = "ABC72961"
boolean b = stringToTest.contains("ABC");
http://www.tutorialspoint.com/java/lang/string_contains.htm
You can use the String indexOf command like this:
int result = someString.indexOf("ABC72961")
result will be -1 if there are no matches.
If there is a match, the result will be the index where the match starts.
I have couple of similar strings. I want to extract the numbers from them, add the numbers and convert it back to the same string format.
And the logic should be generic, i.e., it should work for any given strings.
Example:
String s1 = "1/9"; String s2 = "12/4"; The total of the above two Strings should be "13/13" (String again)
I know how to extract numbers from any given String. I referred: How to extract numbers from a string and get an array of ints?
But I don't know how to put them up back again to the same String format.
Can any one please help me over this?
Note: the string format can be anything, I have just taken an example for explanation.
Take a look at this:
public class StringTest {
public static void main(String[] args) {
String divider = "/";
String s1 = "1/9";
String s2 = "12/4";
String[] fragments1 = s1.split(divider);
String[] fragments2 = s2.split(divider);
int first = Integer.parseInt(fragments1[0]);
first += Integer.parseInt(fragments2[0]);
int second = Integer.parseInt(fragments1[1]);
second += Integer.parseInt(fragments2[1]);
String output = first + divider + second;
System.out.println(output);
}
}
The code prints:
13/13
Using a regex (and Markus' code)
public class StringTest {
public static void main(String[] args) {
String s1 = "1/9";
String s2 = "12&4";
String[] fragments1 = s1.split("[^\\d]");
String[] fragments2 = s2.split("[^\\d]");
int first = Integer.parseInt(fragments1[0]);
first += Integer.parseInt(fragments2[0]);
int second = Integer.parseInt(fragments1[1]);
second += Integer.parseInt(fragments2[1]);
String output = first + divider + second;
System.out.println(output);
}
}
You should be able to get from here to joining back from an array. If you're getting super fancy, you'll need to use regular expression capture groups and store the captured delimiters somewhere.
First, split your strings into matches and non-matches:
public static class Token {
public final String text;
public final boolean isMatch;
public Token(String text, boolean isMatch) {
this.text = text;
this.isMatch = isMatch;
}
#Override
public String toString() {
return text + ":" + isMatch;
}
}
public static List<Token> tokenize(String src, Pattern pattern) {
List<Token> tokens = new ArrayList<>();
Matcher matcher = pattern.matcher(src);
int last = 0;
while (matcher.find()) {
if (matcher.start() != last) {
tokens.add(new Token(src.substring(last, matcher.start()), false));
}
tokens.add(new Token(src.substring(matcher.start(), matcher.end()), true));
last = matcher.end();
}
if (last < src.length()) {
tokens.add(new Token(src.substring(last), false));
}
return tokens;
}
Once this is done, you can create lists you can iterate over and process.
For example, this code:
Pattern digits = Pattern.compile("\\d+");
System.out.println(tokenize("1/2", digits));
...outputs:
[1:true, /:false, 2:true]
Damn quick and dirty not relying on knowing which separator is used. You have to make sure, m1.group(2) and m2.group(2) are equal (which represents the separator).
public static void main(String[] args) {
String s1 = "1/9";
String s2 = "12/4";
Matcher m1 = Pattern.compile("(\\d+)(.*)(\\d+)").matcher(s1);
Matcher m2 = Pattern.compile("(\\d+)(.*)(\\d+)").matcher(s2);
m1.matches(); m2.matches();
int sum1 = parseInt(m1.group(1)) + parseInt(m2.group(1));
int sum2 = parseInt(m2.group(3)) + parseInt(m2.group(3));
System.out.printf("%s%s%s\n", sum1, m1.group(2), sum2);
}
Consider function:
public String format(int first, int second, String separator){
return first + separator + second;
}
then:
System.out.println(format(6, 13, "/")); // prints "6/13"
Thanks #remus. Reading your logic I was able to build the following code. This code solves the problem for any given strings having same format.
public class Test {
public static void main(String[] args) {
ArrayList<Integer> numberList1 = new ArrayList<Integer>();
ArrayList<Integer> numberList2 = new ArrayList<Integer>();
ArrayList<Integer> outputList = new ArrayList<Integer>();
String str1 = "abc 11:4 xyz 10:9";
String str2 = "abc 9:2 xyz 100:11";
String output = "";
// Extracting numbers from the two similar string
Pattern p1 = Pattern.compile("-?\\d+");
Matcher m = p1.matcher(str1);
while (m.find()) {
numberList1.add(Integer.valueOf(m.group()));
}
m = p1.matcher(str2);
while (m.find()) {
numberList2.add(Integer.valueOf(m.group()));
}
// Numbers extracted. Printing them
System.out.println("List1: " + numberList1);
System.out.println("List2: " + numberList2);
// Adding the respective indexed numbers from both the lists
for (int i = 0; i < numberList1.size(); i++) {
outputList.add(numberList1.get(i) + numberList2.get(i));
}
// Printing the summed list
System.out.println("Output List: " + outputList);
// Splitting string to segregate numbers from text and getting the format
String[] template = str1.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
// building the string back using the summed list and format
int counter = 0;
for (String tmp : template) {
if (Test.isInteger(tmp)) {
output += outputList.get(counter);
counter++;
} else {
output += tmp;
}
}
// Printing the output
System.out.println(output);
}
public static boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch (NumberFormatException e) {
return false;
}
return true;
}
}
output:
List1: [11, 4, 10, 9]
List2: [9, 2, 100, 11]
Output List: [20, 6, 110, 20]
abc 20:6 xyz 110:20
I am working on a project and I dont know how to properly parse some input for example a1 = ("hello" + "World"). a1 is a cell that I made and i am trying to at the end put helloworld into that cell. This is one of my classes that I use parse input. When I use numbers it works fine but not with Strings. Im just trying to be able to parse an input like ("hi" + "man") to himan. I just want to be able to parse out the spaces and the plus sign and make himan into a single string.
import java.util.Scanner;
public class ParseInput {
private static String inputs;
static int col;
private static int row;
private static String operation;
private static Value field;
public static void parseInput(String input){
//splits the input at each regular expression match. \w is used for letters and \d && \D for integers
inputs = input;
Scanner tokens = new Scanner(inputs);
String[] strings = input.split("=");
String s1 = strings[0].trim(); // a1
String s2 = strings[1].trim(); // "Hello" + "World"
strings = s2.split("\\+");
String s3 = strings[0].trim().replaceAll("^\"", "").replaceAll("\"$", ""); // Hello
String s4 = strings[1].trim().replaceAll("^\"", "").replaceAll("\"$", ""); // World
String field = s3 + s4;
String colString = s1.replaceAll("[\\d]", ""); // a
String rowString = s1.replaceAll("[\\D]", ""); // 1
int col = colString.charAt(0) - 'a'; // 0
int row = Integer.parseInt(rowString);
TextValue fieldvalue = new TextValue(field);
Spreadsheet.changeCell(row, col, fieldvalue);
String none0 = tokens.next();
#SuppressWarnings("unused")
String none1 = tokens.next();
operation = tokens.nextLine().substring(1);
String[] holder = new String[2];
String regex = "(?<=[\\w&&\\D])(?=\\d)";
holder = none0.split(regex);
row = Integer.parseInt(holder[1]);
col = 0;
int counter = -1;
char temp = holder[0].charAt(0);
char check = 'a';
while(check <= temp){
if(check == temp){
col = counter +1;
}
counter++;
check = (char) (check + 1);
}
System.out.println(col);
System.out.println(row);
System.out.println(operation);
setField(Value.parseValue(operation));
Spreadsheet.changeCell(row, col, fieldvalue);
}
public static Value getField() {
return field;
}
public static void setField(Value field) {
ParseInput.field = field;
}
}
If you're trying to remove spaces, it's a one-liner...
input = input.replaceAll("[\\s+\"]", "");
The other way to do this would be to simply remove all "non word" chars (defined as 0-9, a-z, A-Z and the underscore):
input = input.replaceAll("\\W", "");
Use a StringBuilder. String is immutable in Java, which means you will be creating a new instance every time you want to combine two strings. Use the append() method (it accepts just about anything) to add something onto the end.
StringBuilder input = "";
input.append("hel").append("lo");
Here is the documentation for it. Take a look.