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.
Related
Characters of given string must be sorted according to the order defined by another pattern string. Requirements for complexity O(n + m) where n is length of string and m is length of pattern.
Example:
Pattern: 1234567890AaBbCcDdEeFfGgHh
String: dH7ee2D6a341Fb9Ea20dhC1g7ca32Ba2Gac5f76A2g
Result: 112222233456677790AaaaaaBbCccDddEeeFfGggHh
Pattern has all characters of the string and each one appears in pattern only once.
My code:
// Instances of possible values for input:
String pattern = "1234567890AaBbCcDdEeFfGgHh";
String string = "dH7ee2D6a341Fb9Ea20dhC1g7ca32Ba2Gac5f76A2g";
// Builder to collect characters for sorted result:
StringBuilder result = new StringBuilder();
// Hash table based on characters from pattern to count occurrence of each character in string:
Map<Character, Integer> characterCount = new LinkedHashMap<>();
for (int i = 0; i < pattern.length(); i++) {
// Put each character from pattern and initialize its counter with initial value of 0:
characterCount.put(pattern.charAt(i), 0);
}
// Traverse string and increment counter at each occurrence of character
for (int i = 0; i < string.length(); i++) {
char ch = string.charAt(i);
Integer count = characterCount.get(ch);
characterCount.put(ch, ++count);
}
// Traverse completed dictionary and collect sequentially all characters collected from string
for (Map.Entry<Character, Integer> entry : characterCount.entrySet()) {
Integer count = entry.getValue();
if (count > 0) {
Character ch = entry.getKey();
// Append each character as many times as it appeared in string
for (int i = 0; i < count; i++) {
result.append(ch);
}
}
}
// Get final result from builder
return result.toString();
Is this code optimal? Is there any way to improve this algorithm? Do I understand correctly that it satisfies the given complexity O(n + m)?
Not sure if timing wise yours or mine is faster.
But here's an alternative:
import java.math.BigDecimal;
class Playground {
public static void main(String[ ] args) {
String pattern = "1234567890AaBbCcDdEeFfGgHh";
String s = "dH7ee2D6a341Fb9Ea20dhC1g7ca32Ba2Gac5f76A2g";
long startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (char c : pattern.toCharArray()) {
sb.append(s.replaceAll("[^" + c + "]", ""));
}
System.out.println(sb.toString());
BigDecimal elapsedTime =
new BigDecimal( String.valueOf(System.nanoTime() - startTime)
)
.divide(
new BigDecimal( String.valueOf(1_000_000_000)
)
);
System.out.println(elapsedTime + " seconds");
}
}
Explanation:
For each character in pattern, use a String's regex based replaceAll method to replace all characters except the current one with an empty string. Rinse and repeat. That will leave you with the count of each character in original intact, ordered by the character sequence of pattern.
Outputs:
112222233456677790AaaaaaBbCccDddEeeFfGggHh
0.021151652 seconds
(The timing is somewhat subjective. It came from the Sololearn Java Playground. It obviously depends on the current load on their servers)
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]
I need to write a program that should ask two strings from user and show the common characters in this.
It must not have duplicates: even if ‘a’ is found more than once in both strings, it should be displayed only once.
My Java knowledge is very limited, so I'm not looking for efficiency but for understandability.
Here is what I came up with at the moment.
//Get String 1
System.out.print( "Enter a string: " );
string1 = sc.next();
//Get String 2
System.out.print( "Enter another string: " );
string2 = sc.next();
System.out.print ( "Common characters: " );
//Common chars
for ( a = 0 ; a < string1.length() ; a++){
for ( b = 0 ; b < string2.length() ; b++){
if ( string1.charAt(a) == string2.charAt(b) ){
System.out.print(string1.charAt(a));
}
Can anyone help me ?
You can use the chars() stream of the input string, e.g.:
public class StringCharCount {
public static void main(final String[] args) {
final String s1 = args[0];
final String s2 = args[1];
s1.chars()
.distinct()
.mapToObj(ch -> String.valueOf((char) ch))
.filter(s2::contains)
.forEach(System.out::println);
}
}
This works with Java 8 or later.
chars() creates a stream of characters from the string
distinct() ensures, that each value occurs only once
mapToObj(...) is required, because the String#contains() method requires a String as input. So we are converting the stream value to a String. Unfortunately, Java has issues with the primitive types, so the stream of chars is in fact a stream of int. So we have to cast each value to char.
forEach(...) prints each value to System.out
I would use a Set<Character>. This would naturally handle the duplicate issue and has a simple retainAll method to do the heavy lifting for you.
private Set<Character> characterSet(String s) {
Set<Character> set = new HashSet<>();
// Put each character in the string into the set.
for (int i = 0; i < s.length(); i++) {
set.add(s.charAt(i));
}
return set;
}
public Set<Character> common(String a, String b) {
// Make a set out of each string.
Set<Character> aSet = characterSet(a);
Set<Character> bSet = characterSet(b);
// Work out the common characters using retainAll.
Set<Character> common = new HashSet<>(aSet);
common.retainAll(bSet);
return common;
}
public void test(String[] args) throws Exception {
System.out.println(common("abcdef", "afxyzfffaa"));
}
You can use Set
String str1 = "abcdefg";
String str2 = "abcaaadefg";
StringBuilder result = new StringBuilder();
Set<Character> sets = new HashSet<Character>();
for(char ch : str1.toCharArray()){//init
sets.add(ch);
}
for(char ch : str2.toCharArray()){
if(sets.contains(ch)){//str1 char contains str2 char
result.append(ch);
sets.remove(ch);//avoid duplicates
}
}
System.out.println(result.toString());
I am new to regular expressions. I have a string named encryptId (does not contain |) and I want to append the | character after every 20 characters of this string, using the encryptId.replace/replaceAll(Regex,Pattern) function in Java. But it should never have \ at the end of the string.
Thanks for your help.
EDIT:
The reason I want to use replace and replaceAll functions particularly is because I have to use that in velocity template mananger. And there we can use common String functions but can't write whole java code.
My current solution is shown below
encryptId = encryptId.replaceAll("(.{20})","$1|");
if(encryptId.charAt(encryptId.length() - 1)=='|') {
encryptId = encryptId.substring(0,encryptId.length()-1);
}
I need to get rid of this if statement so that It would be just a string function.
You asked how to do it with replaceAll: I say don't. Regular expressions are not always the best approach to string manipulation problems.
You can efficiently build the new string by taking 20 character blocks from encryptId and appending them to a StringBuilder, optionally appending the pipe if it will not be at the end of the string:
String method(String encryptId) {
StringBuilder sb = new StringBuilder(encryptId.length() + encryptId.length() / 20);
for (int i = 0; i < encryptId.length(); i += 20) {
int end = Math.min(i + 20, encryptId.length());
sb.append(encryptId, i, end);
if (end != encryptId.length()) {
sb.append('|');
}
}
return sb.toString();
}
You can use String.toCharArray:
String s = "..."; //your string
int i = 0;
StringBuilder res = new StringBuilder("");
for (char c : s.toCharArray()){
res.append(c);
i++;
if (i % 20 == 0 && i != s.length()){
res.append("|");
}
}
System.out.println(res.toString());
res will have your first String with an | every 20 characters but not at the end of the String.
This can be done via regular expressions as follows
static String enterADelimiter(String str, String delimiter, int after) {
String regex = "(.{" + after +"})(?!$)";
String replacement = "$1" + delimiter;
return str.replaceAll(regex, replacement);
}
Just use
enterADelimiter(yourString, "|", 20)
This will return correct solution. Explantion
( Start group 1
. Match Anything
{after} after times
) End group 1
(?!$) Don't match if at end of String
Regex may complicate things more. You can also try to use StringBuilder for this:
String encryptId = "test";
StringBuilder builder = new StringBuilder(encryptId);
int insertAfter = 20;
for(int i = encryptId.length(); i > 0 ; i--) {
if (i % insertAfter == 0 && i != encryptId.length()) {
builder.insert(i, "|");
}
}
Well, this is my first time get here.
I'm trying to figure out the correct way to replace number into letter.
In this case, I need two steps.
First, convert letter to number. Second, restore number to word.
Words list: a = 1, b = 2, f = 6 and k = 11.
I have word: "b a f k"
So, for first step, it must be: "2 1 6 11"
Number "2 1 6 11" must be converted to "b a f k".
But, I failed at second step.
Code I've tried:
public class str_number {
public static void main(String[] args){
String word = "b a f k";
String number = word.replace("a", "1").replace("b","2").replace("f","6").replace("k","11");
System.out.println(word);
System.out.println(number);
System.out.println();
String text = number.replace("1", "a").replace("2","b").replace("6","f").replace("11","k");
System.out.println(number);
System.out.println(text);
}
}
Result:
b a f k
2 1 6 11
2 1 6 11
b a f aa
11 must be a word "k", but it's converted to "aa"
What is the right way to fix this?
Or do you have any other ways to convert letter to number and vice versa?
Thank you.
It would be good to write methods for conversion between number and letter format. I would write some code like this and use it generally instead of hard coding replace each time.
public class test {
static ArrayList <String> letter = new ArrayList<String> ();
static ArrayList <String> digit = new ArrayList<String> ();
public static void main(String[] args) {
createTable();
String test="b a f k";
String test1="2 1 6 11";
System.out.println(letterToDigit(test));
System.out.println(digitToLetter(test1));
}
public static void createTable()
{
//Create all your Letter to number Mapping here.
//Add all the letters and digits
letter.add("a");
digit.add("1");
letter.add("b");
digit.add("2");
letter.add("c");
digit.add("3");
letter.add("d");
digit.add("4");
letter.add("e");
digit.add("5");
letter.add("f");
digit.add("6");
letter.add("g");
digit.add("7");
letter.add("h");
digit.add("8");
letter.add("i");
digit.add("9");
letter.add("j");
digit.add("10");
letter.add("k");
digit.add("11");
letter.add("l");
digit.add("12");
letter.add("m");
digit.add("13");
letter.add("n");
digit.add("14");
letter.add("o");
digit.add("14");
letter.add("p");
digit.add("15");
//Carry so on till Z
}
public static String letterToDigit(String input)
{
String[] individual = input.split(" ");
String result="";
for(int i=0;i<individual.length;i++){
if(letter.contains(individual[i])){
result+=Integer.toString(letter.indexOf(individual[i])+1)+ " ";
}
}
return result;
}
public static String digitToLetter(String input)
{
String[] individual = input.split(" ");
String result="";
for(int i=0;i<individual.length;i++){
if(digit.contains(individual[i])){
result+=letter.get(digit.indexOf(individual[i])) + " ";
}
}
return result;
}
}
I would actually not use replace in this case.
A more generic solution would be to simply convert it to a char and subtract the char a from it.
int n = word.charAt(0) - 'a' + 1;
This should return an int with the value you are looking for.
If you want this to be an string you can easily do
String s = Integer.parseInt(word.charAt(0) - 'a' + 1);
And as in your case you are doing a whole string looping through the length of it and changing all would give you the result
String s = "";
for(int i = 0; i < word.length(); i++) {
if(s.charAt(i) != ' ') {
s = s + Integer.toString(word.charAt(i) - 'a' + 1) + " ";
}
}
and then if you want this back to an String with letters instead
String text = "";
int temp = 0;
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == ' ') {
text = text + String.valueOf((char) (temp + 'a' - 1));
temp = 0;
} else if {
temp = (temp*10)+Character.getNumericValue(s.charAt(i));
}
}
You can just reverse the replacement:
String text = number.replace("11","k").replace("2","b").replace("6","f").replace("1","a");
Simplest solution IMO.
When adding other numbers, first replace these with two digits, then these with one.
Replace this:
String text = number.replace("1", "a").replace("2","b").replace("6","f").replace("11","k");
By this:
String text = number.replace("11","k").replace("1", "a").replace("2","b").replace("6","f");
Right now, the first replace you're doing: ("1", "a")
is invalidating the last one: ("11","k")
I think you would need to store the number as an array of ints. Otherwise, there is no way of knowing if 11 is aa or k. I would create a Map and then loop over the characters in the String. You could have one map for char-to-int and one for int-to-char.
Map<Character,Integer> charToIntMap = new HashMap<Character,Integer>();
charToIntMap.put('a',1);
charToIntMap.put('b',2);
charToIntMap.put('f',6);
charToIntMap.put('k',11);
Map<Integer,Character> intToCharMap = new HashMap<Integer,Character>();
intToCharMap.put(1,'a');
intToCharMap.put(2,'b');
intToCharMap.put(6,'f');
intToCharMap.put(11,'k');
String testStr = "abfk";
int[] nbrs = new int[testStr.length()];
for(int i = 0; i< testStr.length(); i++ ){
nbrs[i] = charToIntMap.get(testStr.charAt(i));
}
StringBuilder sb = new StringBuilder();
for(int num : nbrs){
sb.append(num);
}
System.out.println(sb.toString());
//Reverse
sb = new StringBuilder();
for(int i=0; i<nbrs.length; i++){
sb.append(intToCharMap.get(nbrs[i]));
}
System.out.println(sb.toString());
This failed because the replace("1", "a") replaced both 1s with a characters. The quickest fix is to perform the replace of all the double-digit numbers first, so there are no more double-digit numbers left when the single-digit numbers get replaced.
String text = number.replace("11","k").replace("1", "a").
replace("2","b").replace("6","f");