I have a method for the phone number masking. I need to replace all digits with stars except the last 4.
Sample inputs would be: +91 (333) 444-5678 and +1(333) 456-7890. Outputs should look this way:
But my output actually looks like this:
So here is my code:
public static String maskPhoneNumber(String inputPhoneNum){
return inputPhoneNum.replaceAll("\\(", "-")
.replaceAll("\\)", "-")
.replaceAll(" ", "-")
.replaceAll("\\d(?=(?:\\D*\\d){4})", "*");
}
My method works with different number of digits in country codes, but it breaks in cases when instead of a space between digits there are brackets near the country code (triad after it).
I would be grateful for some hints on how I can improve my approach!
Currently, you replace each individual space, ( and ) with a -. You need to replace all consecutive occurrences with 1 hyphen.
Use
public static String maskPhoneNumber(String inputPhoneNum){
return inputPhoneNum.replaceAll("[()\\s]+", "-")
.replaceAll("\\d(?=(?:\\D*\\d){4})", "*");
}
See this Java demo.
The +91 (333) 444-5678 turns into +**-***-***-5678 and +1(333) 456-7890 turns into +*-***-***-7890.
The [()\s]+ pattern matches 1 or more (+) consecutive (, ) or whitespace chars. See the "normalization" step regex demo and the final step demo.
There is a dedicated API in the language itself for that (in the form of appendReplacement)
String test = "+91 (333) 444-5678";
test = test.replaceAll("[()\\s]+", "-");
Pattern p = Pattern.compile("\\d+(?!\\d*$)");
Matcher m = p.matcher(test);
StringBuilder sb = new StringBuilder(); // +**-***-***-5678
for (; m.find();) {
m.appendReplacement(sb, m.group().replaceAll(".", "*"));
}
m.appendTail(sb);
System.out.println(sb.toString());
Related
This code seems to work perfectly, but I'd love to clean it up with regex.
public static void main(String args[]) {
String s = "IAmASentenceInCamelCaseWithNumbers500And1And37";
System.out.println(unCamelCase(s));
}
public static String unCamelCase(String string) {
StringBuilder newString = new StringBuilder(string.length() * 2);
newString.append(string.charAt(0));
for (int i = 1; i < string.length(); i++) {
if (Character.isUpperCase(string.charAt(i)) && string.charAt(i - 1) != ' '
|| Character.isDigit(string.charAt(i)) && !Character.isDigit(string.charAt(i - 1))) {
newString.append(' ');
}
newString.append(string.charAt(i));
}
return newString.toString();
}
Input:
IAmASentenceInCamelCaseWithNumbers500And1And37
Output:
I Am A Sentence In Camel Case With Numbers 500 And 1 And 37
I'm not a fan of using that ugly if statement, and I'm hoping there's a way to use a single line of code that utilizes regex. I tried for a bit but it would fail on words with 1 or 2 letters.
Failing code that doesn't work:
return string.replaceAll("(.)([A-Z0-9]\\w)", "$1 $2");
The right regex and code to do your job is this.
String s = "IAmASentenceInCamelCaseWithNumbers500And1And37";
System.out.println("Output: " + s.replaceAll("[A-Z]|\\d+", " $0").trim());
This outputs,
Output: I Am A Sentence In Camel Case With Numbers 500 And 1 And 37
Editing answer for query asked by OP in comment:
If input string is,
ThisIsAnABBRFor1Abbreviation
Regex needs a little modification and becomes this, [A-Z]+(?![a-z])|[A-Z]|\\d+ for handling abbreviation.
This code,
String s = "ThisIsAnABBRFor1Abbreviation";
System.out.println("Input: " + s.replaceAll("[A-Z]+(?![a-z])|[A-Z]|\\d+", " $0").trim());
Gives expected output as per OP ZeekAran in comment,
Input: This Is An ABBR For 1 Abbreviation
You may use this lookaround based regex solution:
final String result = string.replaceAll(
"(?<=\\S)(?=[A-Z])|(?<=[^\\s\\d])(?=\\d)", " ");
//=> I Am A Sentence In Camel Case With Numbers 500 And 1 And 37
RegEx Demo
RegEx Details:
Regex matches either of 2 conditions and replaces it with a space. It will ignore already present spaces in input.
(?<=\\S)(?=[A-Z]): Previous char is non-space and next char is a uppercase letter
|: OR
(?<=[^\\s\\d])(?=\\d): previous char is non-digit & non-space and next one is a digit
I think you can try this
let str = "IAmASentenceInCamelCaseWithNumbers500And1And37";
function unCamelCase(str){
return str.replace(/(?:[A-Z]|[0-9]+)/g, (m)=>' '+m.toUpperCase()).trim();
}
console.log(unCamelCase(str));
Explanation
(?:[A-Z]|[0-9]+)
?: - Non capturing group.
[A-Z] - Matches any one capital character.
'|' - Alternation (This works same as Logical OR).
[0-9]+ - Matches any digit from 0-9 one or more time.
P.S Sorry for the example in JavaScript but same logic can be achived in JAVA pretty easily.
what is the regular expression so I can keep only the LAST numbers at the END of a String?
For example
Test123 -> 123
T34est56 -> 56
123Test89 -> 89
Thanks
I tried
str.replaceAll("[^A-Za-z\\s]", ""); but this removes all the numbers of the String.
I also tried str.replaceAll("\\d*$", ""); but this returns the following:
Test123 -> Test
T34est56 -> T34est
123Test89 -> 123Test
I want exactly the opposite.
Getting group of the last integers in line and then replacing string with that group seems to work:
String str = "123Test89";
String result = str.replaceAll(".*[^\\d](\\d+$)", "$1");
System.out.println(result);
This outputs:
89
You can use replaceFirst() to remove everything (.*) up to the last non-digit (\\D):
s = s.replaceFirst(".*\\D", "");
Complete example:
public class C {
public static void main(String args[]) {
String s = "T34est56";
s = s.replaceFirst(".*\\D", "");
System.out.println(s); // 56
}
}
You could use a regex like this:
String result = str.replaceFirst(".*?(\\d+$)", "$1");
Try it online.
Explanation:
.*: Any amount of leading characters
?: Optionally. This makes sure the regex part after it ((\\d+$)) has priority over the .*. Without the ?, every test case would only return the very last digit (i.e. 123Test89 would return 9 instead of 89).
\\d+: One or more digits
$: At the very end of the string
(...): Captured in a capture group
Which is then replaced with:
$1: The match of the first capture group (so the trailing digits)
To perhaps make it slightly more clear, you could add a leading ^ to the regex: "^.*?(\\d+$)", although it's not really necessary because .* already matches every leading character.
I like to use the Pattern and Matcher API:
Pattern pattern = Pattern.compile("[1-9]*$");
Matcher matcher = pattern.matcher("Test123");
if (matcher.find()) {
System.out.println(matcher.group()); // 123
}
I think use /.*?(\d+)$/, it will work.
This code doesn't seem doing the right job. It removes the spaces between the words!
input = scan.nextLine().replaceAll("[^A-Za-z0-9]", "");
I want to remove all extra spaces and all numbers or abbreviations from a string, except words and this character: '.
For Example:
input: 34 4fF$##D one 233 r # o'clock 329riewio23
returns: one o'clock
public static String filter(String input) {
return input.replaceAll("[^A-Za-z0-9' ]", "").replaceAll(" +", " ");
}
The first replace replaces all characters except alphabetic characters, the single-quote, and spaces. The second replace replaces all instances of one or more spaces, with a single space.
Your solution doesn't work because you don't replace numbers and you also replace the ' character.
Check out this solution:
Pattern pattern = Pattern.compile("[^| ][A-Za-z']{2,} ");
String input = scan.nextLine();
Matcher matcher = pattern.matcher(input);
StringBuilder result = new StringBuilder();
while (matcher.find()) {
result.append(matcher.group());
}
System.out.println(result.toString());
It looks for the beginning of the string or a space ([^| ]) and then takes all the following characters ([A-Za-z']). However, it only takes the word if there are 2 or more charactes ({2,}) and there has to be a trailing space.
If you want to just extract that time information use this regex group match:
input = scan.nextLine();
Pattern p = Pattern.compile("([a-zA-Z]{3,})\\s.*?(o'clock)");
Matcher m = p.matcher(input);
if (m.find()) {
input = m.group(1) + " " + m.group(2);
}
The regex is quite naive though, and will only work if the input is always of a similar format.
I am new to regular expression syntax, after one whole day digging on the google, still can't find a good regex in java to extract the thing I want from a string...
for example:I have a
stringA = "-3.5 + 2 * 3 / 2"
stringB = "2 * 3 / 2 - 3.5";
the regex i used was
regex="[\\+\\-\\*\\/]", -->choose +,-,*,or / from the target;
by doing this, I am able to capture ANY signs in the string including negative sign.
However, I was to capture the negative sign(-) only when it is following by a whitespace.
That is, I want the result from
string A as [ +, *, /], these three signs and stringB as [ *, / , -]
I realized I only need to add another condition into regex for the negative sign such as
regex = "[\\+{\\-\\s}\\*\\/]" ---> I want to choose same thing but with
extra condition "-"sign has to follow by a whitespace.
the square bracket does not work like this way..Is there anyone can kindly guide my how to add another condition into the original regex? or write a new regex to qualify the need? Thank you so much in advance.
Chi, this might be the simple regex you're looking for:
[+*/]|(?<=\s)-
How does it work?
There is an alternation | in the middle, which is a way of saying "match this or match that."
On the left, the character class [+*/] matches one character that is a +, * or /
On the right, the lookbehind (?<=\s) asserts "preceded by a whitespace character", then we match a minus.
How to use it?
List<String> matchList = new ArrayList<String>();
try {
Pattern regex = Pattern.compile("[+*/]|(?<=\\s)-");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
matchList.add(regexMatcher.group());
}
} catch (PatternSyntaxException ex) {
// Syntax error in the regular expression
}
If you are interested, you may want to read up on regex lookaheads and lookbehinds.
Let me know if you have any question.
What you can do is ditch the class (the [] enclosed Pattern), use OR instead, and use a negative lookahead for your minus sign, to avoid for it to be followed by a digit:
String input0 = "2 * 3 / 2 - 3.5";
String input1 = "-3.5 + 2 * 3 / 2";
Pattern p = Pattern.compile("\\+|\\-(?!\\d)|\\*|/");
Matcher m = p.matcher(input0);
while (m.find()) {
System.out.println(m.group());
}
System.out.println();
m = p.matcher(input1);
while (m.find()) {
System.out.println(m.group());
}
Output
*
/
-
+
*
/
Yet another solution.
Maybe you want to catch the minus sign regardless of white spaces and rather depending on its meaning, i. e. a binary-minus operator and not the minus sign before the numbers.
You could have the case where you could have a binary-minus without any space at all, like in 3-5 or you could have a minus sign before the number with a space between them (which it is allowed in many programming languages, Java included). So, in order to catch your tokens properly (positive-negative-numbers and binary-operators) you can try this:
public static void main(String[] args) {
String numberPattern = "(?:-? *\\d+(?:\\.\\d+)?(?:E[+-]?\\d+)?)";
String opPattern = "[+*/-]";
Pattern tokenPattern = Pattern.compile(numberPattern + "|" + opPattern);
String stringA = "-3.5 + -2 * 3 / 2";
Matcher matcher = tokenPattern.matcher(stringA);
while(matcher.find()) {
System.out.println(matcher.group().trim());
}
}
Here you are catching operators AND ALSO operands, regardless of white spaces. If you only need the binary operators, just filter them.
Try with the string "-3.5+-2*3/2" (without spaces at all) and you'll have your tokens anyway.
Try String#replaceAll(). Its very simple pattern.
// [any digit] or [minus followed by any digit] or [decimal]
String regex = "(\\d|-\\d|\\.)";
String stringA = "-3.5 + 2 * 3 / 2";
String stringA1 = stringA.replaceAll(regex, "").trim();
System.out.println(stringA1);
String stringB = "2 * 3 / 2 - 3.5";
String stringB1 = stringB.replaceAll(regex, "").trim();
System.out.println(stringB1);
output
+ * /
* / -
Note : You can get all the operators using String#split("\\s+").
I was a exercise to do . "Sequences of characters - passwords, which from left to right consists of 3 consecutive digits, 4 letters (the English alphabet) consecutive, and one or more characters from the set {*, ^,%, #, ~,!, &, |, #, $}." I do it , but i isnt work :/
public class regex {
public static void main(String[] args) {
String regex = "[\\d]{3}[a-aZ-Z]{4}[,#!%]+";
String txt = "394aZbr#";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(txt);
while(m.find()){
String s = m.group();
System.out.println("pass : " + s);
}
Result of my exrcise :
pass: 493ahTz#
Could you help me ?
[\\d]{3}[a-aZ-Z]{4}[,#!%]+
Do not use [] if you are only using one \d, you can use {3} with \d directly.
[a-aZ-Z] that is exactly the same as [aZ], you must use [a-zA-Z]
The last part seems good but you may want to add all the chars that you mentioned before.
Result: \\d{3}[a-zA-Z]{4}[,#!%]+