Java Regular Expression : Need Simpler Solution - java

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, "|");
}
}

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.

How to efficiently remove consecutive same characters in a string

I wrote a method to reduce a sequence of the same characters to a single character as follows. It seems its logic is correct while there is a room for improvement in terms of performance, according to my tutor. Could anyone shed some light on this?
Comments of aspects other than performance is also really appreciated.
public class RemoveRepetitions {
public static String remove(String input) {
String ret = "";
String last = "";
String[] stringArray = input.split("");
for(int j=0; j < stringArray.length; j++) {
if (! last.equals(stringArray[j]) ) {
ret += stringArray[j];
}
last = stringArray[j];
}
return ret;
}
public static void main(String[] args) {
System.out.println(RemoveRepetitions.remove("foobaarrbuzz"));
}
}
We can improve the performance by using StringBuilder instead of using string as string operations are costlier. Also, the split function is also not required (it will make the program slower as well).
Here is a way to solve this:
public static String remove(String input)
{
StringBuilder answer = new StringBuilder("");
int N = input.length();
int i = 0;
while (i < N)
{
char c = input.charAt(i);
answer.append( c );
while (i<N && input.charAt(i)==c)
++i;
}
return answer.toString();
}
The idea is to iterate over all characters of the input string and keep appending every new character to the answer and skip all the same consecutive characters.
Possible change which you could think of in your code is:
Time Complexity: Your code is achieving output in O(n) time complexity, which might be the best possible way.
Space Complexity: Your code is using extra memory space which arises due to splitting.
Question to ask: Can you achieve this output, without using the extra space for character array that you get after splitting the string? (as character by character traversal is possible directly on string).
I can provide you the code here but, it would be great if you could try it on your own, once you are done with your attempts
you can lookup for the best solution here (you are almost there)
https://www.geeksforgeeks.org/remove-consecutive-duplicates-string/
Good luck!
As mentioned before, it is much better to access the characters in the string using method String::charAt or at least by iterating a char array retrieved with String::toCharArray instead of splitting the input string into String array.
However, Java strings may contain characters exceeding basic multilingual plane of Unicode (e.g. emojis πŸ˜‚πŸ˜πŸ˜Š, Chinese or Japanese characters etc.) and therefore String::codePointAt should be used. Respectively, Character.charCount should be used to calculate appropriate offset while iterating the input string.
Also the input string should be checked if it's null or empty, so the resulting code may look like this:
public static String dedup(String str) {
if (null == str || str.isEmpty()) {
return str;
}
int prev = -1;
int n = str.length();
System.out.println("length = " + n + " of [" + str + "], real length: " + str.codePointCount(0, n));
StringBuilder sb = new StringBuilder(n);
for (int i = 0; i < n; ) {
int cp = str.codePointAt(i);
if (i == 0 || cp != prev) {
sb.appendCodePoint(cp);
}
prev = cp;
i += Character.charCount(cp); // for emojis it returns 2
}
return sb.toString();
}
A version with String::charAt may look like this:
public static String dedup2(String str) {
if (null == str || str.isEmpty()) {
return str;
}
int n = str.length();
StringBuilder sb = new StringBuilder(n);
sb.append(str.charAt(0));
for (int i = 1; i < n; i++) {
if (str.charAt(i) != str.charAt(i - 1)) {
sb.append(str.charAt(i));
}
}
return sb.toString();
}
The following test proves that charAt fails to deduplicate repeated emojis:
System.out.println("codePoint: " + dedup ("πŸ˜‚πŸ˜‚πŸ˜πŸ˜πŸ˜ŠπŸ˜ŠπŸ˜‚ hello"));
System.out.println("charAt: " + dedup2("πŸ˜‚πŸ˜‚πŸ˜πŸ˜πŸ˜ŠπŸ˜ŠπŸ˜‚ hello"));
Output:
length = 20 of [πŸ˜‚πŸ˜‚πŸ˜πŸ˜πŸ˜ŠπŸ˜ŠπŸ˜‚ hello], real length: 13
codePoint: πŸ˜‚πŸ˜πŸ˜ŠπŸ˜‚ helo
charAt: πŸ˜‚πŸ˜‚πŸ˜πŸ˜πŸ˜ŠπŸ˜ŠπŸ˜‚ helo

How to i mask all string characters except for the last 4 characters in Java using parameters?

i will like to know how do i mask any number of string characters except the last 4 strings.
I want to masked all strings using "X"
For example
Number:"S1234567B"
Result
Number :"XXXXX567B
Thank you guys
Solution 1
You can do it with a regular expression.
This is the shortest solution.
static String mask(String input) {
return input.replaceAll(".(?=.{4})", "X");
}
The regex matches any single character (.) that is followed (zero-width positive lookahead) by at least 4 characters ((?=.{4})). Replace each such single character with an X.
Solution 2
You can do it by getting a char[]1, updating it, and building a new string.
This is the fastest solution, and uses the least amount of memory.
static String mask(String input) {
if (input.length() <= 4)
return input; // Nothing to mask
char[] buf = input.toCharArray();
Arrays.fill(buf, 0, buf.length - 4, 'X');
return new String(buf);
}
1) Better than using a StringBuilder.
Solution 3
You can do it using the repeat​(int count) method that was added to String in Java 11.
This is likely the easiest solution to understand.
static String mask(String input) {
int maskLen = input.length() - 4;
if (maskLen <= 0)
return input; // Nothing to mask
return "X".repeat(maskLen) + input.substring(maskLen);
}
Kotlin extension which will take care of the number of stars that you want to set and also number of digits for ex: you have this string to be masked: "12345678912345" and want to be ****2345 then you will have:
fun String.maskStringWithStars(numberOfStars: Int, numberOfDigitsToBeShown: Int): String {
var stars = ""
for (i in 1..numberOfStars) {
stars += "*"
}
return if (this.length > numberOfDigitsToBeShown) {
val lastDigits = this.takeLast(numberOfDigitsToBeShown)
"$stars$lastDigits"
} else {
stars
}
}
Usage:
companion object{
const val DEFAULT_NUMBER_OF_STARS = 4
const val DEFAULT_NUMBER_OF_DIGITS_TO_BE_SHOWN = 4
}
yourString.maskStringWithStars(DEFAULT_NUMBER_OF_STARS,DEFAULT_NUMBER_OF_DIGITS_TO_BE_SHOWN)
You can do it with the help of StringBuilder in java as follows,
String value = "S1234567B";
String formattedString = new StringBuilder(value)
.replace(0, value.length() - 4, new String(new char[value.length() - 4]).replace("\0", "x")).toString();
System.out.println(formattedString);
You can use a StringBuilder.
StringBuilder sb = new StringBuilder("S1234567B");
for (int i = 0 ; i < sb.length() - 4 ; i++) { // note the upper limit of the for loop
// sets every character to X until the fourth to last character
sb.setCharAt(i, 'X');
}
String result = sb.toString();
My class to mask simple String
class MaskFormatter(private val pattern: String, private val splitter: Char? = null) {
fun format(text: String): String {
val patternArr = pattern.toCharArray()
val textArr = text.toCharArray()
var textI = 0
for (patternI in patternArr.indices) {
if (patternArr[patternI] == splitter) {
continue
}
if (patternArr[patternI] == 'A' && textI < textArr.size) {
patternArr[patternI] = textArr[textI]
}
textI++
}
return String(patternArr)
}
}
Example use
MaskFormatter("XXXXXAAAA").format("S1234567B") // XXXXX567B
MaskFormatter("XX.XXX.AAAA", '.').format("S1234567B") // XX.XXX.567B
MaskFormatter("**.***.AAAA", '.').format("S1234567B") // **.***.567B
MaskFormatter("AA-AAA-AAAA",'-').format("123456789") // 12-345-6789

How to find first character after second dot java

Do you have any ideas how could I get first character after second dot of the string.
String str1 = "test.1231.asdasd.cccc.2.a.2";
String str2 = "aaa.1.22224.sadsada";
In first case I should get a and in second 2.
I thought about dividing string with dot, and extracting first character of third element. But it seems to complicated and I think there is better way.
How about a regex for this?
Pattern p = Pattern.compile(".+?\\..+?\\.(\\w)");
Matcher m = p.matcher(str1);
if (m.find()) {
System.out.println(m.group(1));
}
The regex says: find anything one or more times in a non-greedy fashion (.+?), that must be followed by a dot (\\.), than again anything one or more times in a non-greedy fashion (.+?) followed by a dot (\\.). After this was matched take the first word character in the first group ((\\w)).
Usually regex will do an excellent work here. Still if you are looking for something more customizable then consider the following implementation:
private static int positionOf(String source, String target, int match) {
if (match < 1) {
return -1;
}
int result = -1;
do {
result = source.indexOf(target, result + target.length());
} while (--match > 0 && result > 0);
return result;
}
and then the test is done with:
String str1 = "test..1231.asdasd.cccc..2.a.2.";
System.out.println(positionOf(str1, ".", 3)); -> // prints 10
System.out.println(positionOf(str1, "c", 4)); -> // prints 21
System.out.println(positionOf(str1, "c", 5)); -> // prints -1
System.out.println(positionOf(str1, "..", 2)); -> // prints 22 -> just have in mind that the first symbol after the match is at position 22 + target.length() and also there might be none element with such index in the char array.
Without using pattern, you can use subString and charAt method of String class to achieve this
// You can return String instead of char
public static char returnSecondChar(String strParam) {
String tmpSubString = "";
// First check if . exists in the string.
if (strParam.indexOf('.') != -1) {
// If yes, then extract substring starting from .+1
tmpSubString = strParam.substring(strParam.indexOf('.') + 1);
System.out.println(tmpSubString);
// Check if second '.' exists
if (tmpSubString.indexOf('.') != -1) {
// If it exists, get the char at index of . + 1
return tmpSubString.charAt(tmpSubString.indexOf('.') + 1);
}
}
// If 2 '.' don't exists in the string, return '-'. Here you can return any thing
return '-';
}
You could do it by splitting the String like this:
public static void main(String[] args) {
String str1 = "test.1231.asdasd.cccc.2.a.2";
String str2 = "aaa.1.22224.sadsada";
System.out.println(getCharAfterSecondDot(str1));
System.out.println(getCharAfterSecondDot(str2));
}
public static char getCharAfterSecondDot(String s) {
String[] split = s.split("\\.");
// TODO check if there are values in the array!
return split[2].charAt(0);
}
I don't think it is too complicated, but using a directly matching regex is a very good (maybe better) solution anyway.
Please note that there might be the case of a String input with less than two dots, which would have to be handled (see TODO comment in the code).
You can use Java Stream API since Java 8:
String string = "test.1231.asdasd.cccc.2.a.2";
Arrays.stream(string.split("\\.")) // Split by dot
.skip(2).limit(1) // Skip 2 initial parts and limit to one
.map(i -> i.substring(0, 1)) // Map to the first character
.findFirst().ifPresent(System.out::println); // Get first and print if exists
However, I recommend you to stick with Regex, which is safer and a correct way to do so:
Here is the Regex you need (demo available at Regex101):
.*?\..*?\.(.).*
Don't forget to escape the special characters with double-slash \\.
String[] array = new String[3];
array[0] = "test.1231.asdasd.cccc.2.a.2";
array[1] = "aaa.1.22224.sadsada";
array[2] = "test";
Pattern p = Pattern.compile(".*?\\..*?\\.(.).*");
for (int i=0; i<array.length; i++) {
Matcher m = p.matcher(array[i]);
if (m.find()) {
System.out.println(m.group(1));
}
}
This code prints two results on each line: a, 2 and an empty lane because on the 3rd String, there is no match.
A plain solution using String.indexOf:
public static Character getCharAfterSecondDot(String s) {
int indexOfFirstDot = s.indexOf('.');
if (!isValidIndex(indexOfFirstDot, s)) {
return null;
}
int indexOfSecondDot = s.indexOf('.', indexOfFirstDot + 1);
return isValidIndex(indexOfSecondDot, s) ?
s.charAt(indexOfSecondDot + 1) :
null;
}
protected static boolean isValidIndex(int index, String s) {
return index != -1 && index < s.length() - 1;
}
Using indexOf(int ch) and indexOf(int ch, int fromIndex) needs only to examine all characters in worst case.
And a second version implementing the same logic using indexOf with Optional:
public static Character getCharAfterSecondDot(String s) {
return Optional.of(s.indexOf('.'))
.filter(i -> isValidIndex(i, s))
.map(i -> s.indexOf('.', i + 1))
.filter(i -> isValidIndex(i, s))
.map(i -> s.charAt(i + 1))
.orElse(null);
}
Just another approach, not a one-liner code but simple.
public class Test{
public static void main (String[] args){
for(String str:new String[]{"test.1231.asdasd.cccc.2.a.2","aaa.1.22224.sadsada"}){
int n = 0;
for(char c : str.toCharArray()){
if(2 == n){
System.out.printf("found char: %c%n",c);
break;
}
if('.' == c){
n ++;
}
}
}
}
}
found char: a
found char: 2

Java string -> two numbers

The operation I'm hoping to perform is to go from:
String "32.63578..."
to:
float 32.63
long 578... //where '...' is rest of string
Something like the following in Python:
split = str.find('.')+2
float = str[:split]
long = str[split:]
I'm new to Java, so I began by trying to look up equivalents, however it seems like a more convoluted solution than perhaps a regex would be? Unless there's more similar functions to python than splitting into a char array, and repeatedly iterating over?
Use indexOf and substring methods:
String str = "32.63578";
int i = str.indexOf(".") + 3;
String part1 = str.substring(0, i); // "32.63"
String part2 = str.substring(i); // "578"
float num1 = Float.parseFloat(part1); // 32.63
long num2 = Long.parseLong(part2); // 578
Regular expression alternative:
String str = "32.63578";
String[] parts = str.split("(?<=\\.\\d{2})");
System.out.println(parts[0]); // "32.63"
System.out.println(parts[1]); // "578"
About the regular expression used:
(?<=\.\d{2})
It's positive lookbehind (?<=...). It matches at the position where is preceded by . and 2 digits.
You can use the split method in String if you want to cleanly break the two parts.
However, if you want to have trailing decimals like in your example, you'll probably want to do something like this:
String str = "32.63578...";
String substr1, substr2;
for (int i = 0; i < str.length(); i++)
{
if (str.charAt(i) == '.')
{
substr1 = str.substring(0, i + 3);
substr2 = str.substring(i + 3, str.length());
break;
}
}
//convert substr1 and substr2 here
String s ="32.63578";
Pattern pattern = Pattern.compile("(?<Start>\\d{1,10}.\\d{1,2})(?<End>\\d{1,10})");
Matcher match = pattern.matcher(s);
if (match.find()) {
String start = match.group("Start");
String ending = match.group("End");
System.out.println(start);
System.out.println(ending);
}

Categories