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.
Related
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());
I've searched many post on this forum and to my surprise, I haven't found anyone with a problem like mine.
I have to make a simple calculator for string values from console. Right now,I'm trying to make some regexes to validate the input.
My calculator has to accept numbers with spaces between the operators (only + and - is allowed) but not the ones with spaces between numbers, to sum up:
2 + 2 = 4 is correct, but
2 2 + 2 --> this should make an error and inform user on the console that he put space between numbers.
I've come up with this:
static String properExpression = "([0-9]+[+-]?)*[0-9]+$";
static String noInput = "";
static String numbersFollowedBySpace = "[0-9]+[\\s]+[0-9]";
static String numbersWithSpaces = "\\d+[+-]\\d+";
//I've tried also "[\\d\\s+\\d]";
void validateUserInput() {
Scanner sc = new Scanner(System.in);
System.out.println("Enter a calculation.");
input = sc.nextLine();
if(input.matches(properExpression)) {
calculator.calculate();
} else if(input.matches(noInput)) {
System.out.print(0);
} else if(input.matches(numbersFollowedBySpace)) {
input.replaceAll(" ", "");
calculator.calculate();
} else if(input.matches(numbersWithSpaces))
{
System.out.println("Check the numbers.
It seems that there is a space between the digits");
}
else System.out.println("sth else");
Can you give me a hint about the regex I should use?
To match a complete expression, like 2+3=24 or 6 - 4 = 2, a regex like
^\d+\s*[+-]\s*\d+\s*=\s*\d+$
will do. Look at example 1 where you can play with it.
If you want to match longer expressions like 2+3+4+5=14 then you can use:
^\d+\s*([+-]\s*\d+\s*)+=\s*\d+$
Explanation:
^\d+ # first operand
\s* # 0 or more spaces
( # start repeating group
[+-]\s* # the operator (+/-) followed by 0 or more spaces
\d+\s* # 2nd (3rd,4th) operand followed by 0 or more spaces
)+ # end repeating group. Repeat 1 or more times.
=\s*\d+$ # equal sign, followed by 0 or more spaces and result.
Now, you might want to accept an expression like 2=2 as a valid expression. In that case the repeating group could be absent, so change + into *:
^\d+\s*([+-]\s*\d+\s*)*=\s*\d+$
Look at example 2 for that one.
Try:
^(?:\d+\s*[+-])*\s*\d+$
Demo
Explanation:
The ^ and $ anchor the regex to match the whole string.
I have added \s* to allow whitespace between each number/operator.
I have replaced [0-9] with \d just to simplify it slightly; the two are equivalent.
I'm a little unclear whether you wanted to allow/disallow including = <digits> at the end, since your question mentions this but your attempted properExpression expression doesn't attempt it. If this is the case, it should be fairly easy to see how the expression can be modified to support it.
Note that I've not attempted to solve any potential issues arising out of anything other than regex issues.
Tried as much as possible to keep your logical flow. Although there are other answers which are more efficient but you would've to alter your logical flow a lot.
Please see the below and let me know if you have any questions.
static String properExpression = "\\s*(\\d+\\s*[+-]\\s*)*\\d+\\s*";
static String noInput = "";
static String numbersWithSpaces = ".*\\d[\\s]+\\d.*";
//I've tried also "[\\d\\s+\\d]";
static void validateUserInput() {
Scanner sc = new Scanner(System.in);
System.out.println("Enter a calculation.");
String input = sc.nextLine();
if(input.matches(properExpression)) {
input=input.replaceAll(" ", ""); //You've to assign it back to input.
calculator.calculate(); //Hope you have a way to pass input to calculator object
} else if(input.matches(noInput)) {
System.out.print(0);
} else if(input.matches(numbersWithSpaces)) {
System.out.println("Check the numbers. It seems that there is a space between the digits");
} else
System.out.println("sth else");
Sample working version here
Explanation
The below allows replaceable spaces..
\\s* //Allow any optional leading spaces if any
( //Start number+operator sequence
\\d+ //Number
\\s* //Optional space
[+-] //Operator
\\s* //Optional space after operator
)* //End number+operator sequence(repeated)
\\d+ //Last number in expression
\\s* //Allow any optional space.
Numbers with spaces
.* //Any beginning expression
\\d //Digit
[\\s]+ //Followed by one or more spaces
\\d //Followed by another digit
.* //Rest of the expression
I am using regex to print out a string and adding a new line after a character limit. I don't want to split up a word if it hits the limit (start printing the word on the next line) unless a group of concatenated characters exceed the limit where then I just continue the end of the word on the next line. However when I hit special characters(e.g. +-.,!##$%^&*;) as you'll see when I test my code below, it adds an additional character to the limit for some reason. Why is this?
My function is:
public static String limiter(String str, int lim) {
str = str.trim().replaceAll(" +", " ");
str = str.replaceAll("\n +", "\n");
Matcher mtr = Pattern.compile("(.{1," + lim + "}(\\W|$))|(.{0," + lim + "})").matcher(str);
String newStr = "";
int ctr = 0;
while (mtr.find()) {
if (ctr == 0) {
newStr += (mtr.group());
ctr++;
} else {
newStr += ("\n") + (mtr.group());
}
}
return newStr ;
}
So my input is:
String str = " The 123456789 456789 +-.,!##$%^&*();\\/|<>\"\' fox jumpeded over the uf\n 2 3456 green fence ";
With a character line limit of 7.
It outputs:
456789 +
-.,!##$%
^&*();\/
|<>"
When the correct output should be:
456789
+-.,!##
$%^&*()
;\/|<>"
My code is linked to an online compiler you can run here:
https://ideone.com/9gckP1
You need to replace the (\W|$) with \b as your intention is to match whole words (and \b provides this functionality). Also, since you do not need trailing whitespace on newly created lines, you need to also use \s*.
So, use
Matcher mtr = Pattern.compile("(?U)(.{1," + lim + "}\\b\\s*)|(.{0," + lim + "})").matcher(str);
See demo
Note that (?U) is used here to "fix" the word boundary behavior to keep it in sync with \w (so that diacritics were not considered word characters).
In your pattern, \\W is part of the first capturing group. It is adding this one (non-word) character to the .{1,limit} pattern.
Try with: "(.{1," + lim + "})(\W|$)|(.{0," + lim + "})"
(I can't currently use your regex online compiler)
I am given the String "('allan', 'bob's', 'charles', 'dom')". Now I require this string but in the form "('allan', 'bob''s', 'charles', 'dom')".
Notice I have replaced bob's with bob''s and that is all. My initial solution went along the lines of
String str = "('allan', 'bob's', 'charles', 'dom')";
String[] elements = str.substring(1, str.length()-1).split(", ");
String res = "(";
for (int j = 0; j < elements.length; j++) {
res += "'"+ elements[j].substring(1, elements[j].length()-1).replace("'", "''") + "'" + ((j == elements.length - 1) ? ")" : ",' ");
}
Where res is the final solution. However I am wondering if there is a shorter, more elegant solution to this?
replaceAll will work with "'s" as a regular expression.
public static void main(String[] args) {
String str = "('allan', 'bob's', 'charles', 'dom')";
str = str.replaceAll("'s", "''s");
System.out.println(str);
}
Output :
('allan', 'bob''s', 'charles', 'dom')
It's sounds like you just want to replace a single quote that is between two letters with two single quotes. String.replaceAll() using the regex pattern "(\\w)(['])(\\w)" and replacement string "$1''$3" should get this done for you.
Pattern breakdown:
(\\w) - Capture a letter or number into group 1
([']) - Capture the single quote into group 2
(\\w) - Capture a letter or number into group 3
Replacement string breakdown:
$1 - Capture group 1
'' - Two single quotes
$3 - Capture group 3
Code sample:
public static void main(String[] args) throws Exception {
String str = "('allan', 'bob's', 'charles', 'dom')";
str = str.replaceAll("(\\w)(['])(\\w)", "$1''$3");
System.out.println(str);
}
Results:
('allan', 'bob''s', 'charles', 'dom')
str = str.replace("'", "''").replaceAll("''(.*)?''(, *|\\)$)", "'$1'$2");
(~~) (~~~|~~~~)
Doubling the apostrophes cannot be done on a substring replace (without function-replace), hence must be done first.
Then one can pick out the quoted values, and correct them.
The trailer is either a comma+space or a final closing parenthesis.
.*? takes the shortest sequence.
i would recommend to fix the thing which outputted that string, and:
use escape sequences
use some library for reading/writing the data json or yaml might be good candidates
i have seen to replace "," to "." by using ".$"|",$", but this logic is not working with alphabets.
i need to replace last letter of a word to another letter for all word in string containing EXAMPLE_TEST using java
this is my code
Pattern replace = Pattern.compile("n$");//here got the real problem
matcher2 = replace.matcher(EXAMPLE_TEST);
EXAMPLE_TEST=matcher2.replaceAll("k");
i also tried "//n$" ,"\n$" etc
Please help me to get the solution
input text=>njan ayman
output text=> njak aymak
Instead of the end of string $ anchor, use a word boundary \b
String s = "njan ayman";
s = s.replaceAll("n\\b", "k");
System.out.println(s); //=> "njak aymak"
You can use lookahead and group matching:
String EXAMPLE_TEST = "njan ayman";
s = EXAMPLE_TEST.replaceAll("(n)(?=\\s|$)", "k");
System.out.println("s = " + s); // prints: s = njak aymak
Explanation:
(n) - the matched word character
(?=\\s|$) - which is followed by a space or at the end of the line (lookahead)
The above is only an example! if you want to switch every comma with a period the middle line should be changed to:
s = s.replaceAll("(,)(?=\\s|$)", "\\.");
Here's how I would set it up:
(?=.\b)\w
Which in Java would need to be escaped as following:
(?=.\\b)\\w
It translates to something like "a character (\w) after (?=) any single character (.) at the end of a word (\b)".
String s = "njan ayman aowkdwo wdonwan. wadawd,.. wadwdawd;";
s = s.replaceAll("(?=.\\b)\\w", "");
System.out.println(s); //nja ayma aowkdw wdonwa. wadaw,.. wadwdaw;
This removes the last character of all words, but leaves following non-alphanumeric characters. You can specify only specific characters to remove/replace by changing the . to something else.
However, the other answers are perfectly good and might achieve exactly what you are looking for.
if (word.endsWith("char oldletter")) {
name = name.substring(0, name.length() - 1 "char newletter");
}