I'd like to mask numbers according to pattern. If number is 22123123123 and pattern is xxxxx***xxx the result of masking should be 22123***123. I wrote a code:
private String maskNumberWithPattern(String number) {
char[] pattern = "xxxxx***xxx".toCharArray();
char[] numberInput = number.toCharArray();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < pattern.length; i++) {
if(pattern[i] == '*') {
stringBuffer.append("*");
} else {
stringBuffer.append(numberInput[i]);
}
}
return stringBuffer.toString();
}
Is there some standard api method to achieve that?
It's not clear from your code how your pattern behaves exactly. For example, what should happen if the input String is longer than your pattern? Is there a chance that the pattern does not match? Etc. I don't know such thing...
I guess wildcard patterns or regular expression is the easiest thing you can get here:
private static String maskNumberWithPattern(String number) {
Pattern pattern = Pattern.compile("(\\d{5})(\\d*)(\\d{3})");
Matcher matcher = pattern.matcher(number);
if (matcher.matches()) {
String group = matcher.group(2);
return matcher.group(1) + StringUtils.repeat('*', group.length()) + matcher.group(2);
}
else {
return number;
}
}
Related
I have an input string, consisting of several lines, e.g.:
When I was younger
I never needed
And I was always OK
but it was a long Time Ago
The problem is to invert first letters of all the words which length is more than 3. That is an output must be the following:
when I Was Younger
I Never Needed
and I Was Always OK
But it Was a Long time ago
There is my code:
import java.util.regex.*;
public class Part3_1 {
public static void main(String[] args) {
String str = "When I was younger\r\nI never needed\r\nAnd I was always OK\r\nbut it was a long Time Ago";
System.out.println(convert(str));
}
public static String convert(String str) {
String result = "";
String[] strings = str.split(" ");
String regexLowerCase = "\\b[a-z]{3,}\\b";
String regexLowerCaseInitial = "(\\r\\n)[a-z]{3,}\\b";
String regexUpperCase = "\\b([A-Z][a-z]{2,})+\\b";
String regexUpperCaseInitial = "(\\r\\n)([A-Z][a-z]{2,})\\b";
Pattern patternLowerCase = Pattern.compile(regexLowerCase, Pattern.MULTILINE);
Pattern patternUpperCase = Pattern.compile(regexUpperCase, Pattern.MULTILINE);
Pattern patternLowerCaseInitial = Pattern.compile(regexLowerCaseInitial, Pattern.MULTILINE);
Pattern patternUpperCaseInitial = Pattern.compile(regexUpperCaseInitial, Pattern.MULTILINE);
for (int i = 0; i < strings.length; i++) {
Matcher matcherLowerCase = patternLowerCase.matcher(strings[i]);
Matcher matcherUpperCase = patternUpperCase.matcher(strings[i]);
Matcher matcherLowerCaseInitial = patternLowerCaseInitial.matcher(strings[i]);
Matcher matcherUpperCaseInitial = patternUpperCaseInitial.matcher(strings[i]);
char[] words = strings[i].toCharArray();
if (matcherLowerCase.find() || matcherLowerCaseInitial.find()) {
char temp = Character.toUpperCase(words[0]);
words[0] = temp;
result += new String(words);
} else if (matcherUpperCase.find() || matcherUpperCaseInitial.find()) {
char temp = Character.toLowerCase(words[0]);
words[0] = temp;
result += new String(words);
} else {
result += new String(words);
}
if (i < strings.length - 1) {
result += " ";
}
}
return result;
}
}
Here:
"\\b[a-z]{3,}\\b" is a regular expression, selecting all words in lower case which length is 3 or more symbols,
"\\b([A-Z][a-z]{2,})+\\b" is a regular expression, selecting all words starting from capital letter which length is 3 or more symbols.
Both regular expressions works properly but when we have a line breaks - they do not work. The output of my program execution is following:
when I Was Younger
I Never Needed
And I Was Always OK
but it Was a Long Time ago
As I understood, these regular expressions cannot select words And and but from needed\r\nAnd and OK\r\nbut respectively.
To fix this bug I tried to add new regular expressions "(\\r\\n)[a-z]{3,}\\b" and "(\\r\\n)([A-Z][a-z]{2,})\\b", but they do not work.
How to compose the regular expressions, selecting words after line breaks?
One option would be to split the string on a word break (\b) instead, and then pass the white space through to the final string in the strings array. This removes the need to have separate regex for the different situations, and also the need to add back space characters. This will give you the results you want:
public static String convert(String str) {
String result = "";
String[] strings = str.split("\\b");
String regexLowerCase = "^[a-z]{3,}";
String regexUpperCase = "^[A-Z][a-z]{2,}+";
Pattern patternLowerCase = Pattern.compile(regexLowerCase, Pattern.MULTILINE);
Pattern patternUpperCase = Pattern.compile(regexUpperCase, Pattern.MULTILINE);
for (int i = 0; i < strings.length; i++) {
Matcher matcherLowerCase = patternLowerCase.matcher(strings[i]);
Matcher matcherUpperCase = patternUpperCase.matcher(strings[i]);
char[] words = strings[i].toCharArray();
if (matcherLowerCase.find()) {
char temp = Character.toUpperCase(words[0]);
words[0] = temp;
result += new String(words);
} else if (matcherUpperCase.find()) {
char temp = Character.toLowerCase(words[0]);
words[0] = temp;
result += new String(words);
} else {
result += new String(words);
}
}
return result;
}
Output:
when I Was Younger
I Never Needed
and I Was Always OK
But it Was a Long time ago
Demo on rextester
I want to find a single regex which matches the longest numerical string in a URL.
I.e for the URL: http://stackoverflow.com/1234/questions/123456789/ask, I would like it to return : 123456789
I thought I could use : ([\d]+)
However this returns the first match from the left, not the longest.
Any ideas :) ?
This regex will be used as an input to a strategy pattern, which extracts certain characteristics from urls:
public static String parse(String url, String RegEx) {
Pattern pattern = Pattern.compile(regex);
Matcher m = pattern.matcher(url);
if (m.find()) {
return m.group(1);
}
return null;
}
So it would be much tidier if I could use a single regex. :( –
Don't use regex. Just iterate the characters:
String longest = 0;
int i = 0;
while (i < str.length()) {
while (i < str.length() && !Character.isDigit(str.charAt(i))) {
++i;
}
int start = i;
while (i < str.length() && Character.isDigit(str.charAt(i))) {
++i;
}
if (i - start > longest.length()) {
longest = str.substring(start, i);
}
}
#Andy already gave a non-regex answer, which is probably faster, but if you want to use regex, you must, as #Jan points out, add logic, e.g.:
public String findLongestNumber(String input) {
String longestMatch = "";
int maxLength = 0;
Matcher m = Pattern.compile("([\\d]+)").matcher(input);
while (m.find()) {
String currentMatch = m.group();
int currentLength = currentMatch.length();
if (currentLength > maxLength) {
maxLength = currentLength;
longestMatch = currentMatch;
}
}
return longestMatch;
}
t
Not possible with pure Regex, however I would do it this way (using Stream Max and Regex) :
String url = "http://stackoverflow.com/1234/questions/123456789/ask";
Pattern biggest = Pattern.compile("/(\\d+)/");
Matcher m = biggest.matcher(url);
List<String> matches = new ArrayList<>();
while(m.find()){
matches.add(m.group(1));
}
System.out.println(matches.parallelStream().max((String a, String b) -> Integer.compare(a.length(), b.length())).get());
Will print : 123456789
Which regular expression in java can do these conversions?
"1.54.0.21" to "01540021"
or
"33.5.10.6" to "33051006"
I need to replace .# with 0# and .## with ##
You could try something like...
StringBuilder output = new StringBuilder(8);
String input = "1.54.0.21";
Pattern p = Pattern.compile("\\d+");
Matcher matcher = p.matcher(input);
while (matcher.find()) {
String group = matcher.group();
if (group.length() < 2) {
output.append("0");
}
output.append(group);
}
System.out.println(input);
System.out.println(output);
Which outputs...
1.54.0.21
01540021
Without Regex :
http://rextester.com/LGXETU62790
public static void main(String args[])
{
String str1 = "33.5.9.6";
String str2 = "1.54.0.21";
System.out.println(transform(str1));
System.out.println(transform(str2));
}
private static String transform(String str){
String[] splitted = str.split("\\.");
StringBuilder build = new StringBuilder();
for(String s : splitted){
build.append(String.format("%02d", Integer.parseInt(s)));
}
return build.toString();
}
The only functionality of a regular expression is to match a certain pattern of characters inside a string (or multiline strings).
A regular expression can be used in a find and replace Pattern but only to find the strings you are interested in. When they are found , a Split(), Remove(), Replace(), function will better do it's purpose.
I recommend you : http://gskinner.com/RegExr/
This is an online tool for matching strings with regular expression, and also learning the patterns.
public String getToken(String elem) {
return (elem.size() == 1) ? ("0" + elem) : elem;
}
String[] a = "1.54.0.21".split("\\.");
String o = "", e;
int i = 0, len = a.size();
for (i = 0; i < len; i++) {
o = o + getToken(a[i]);
}
System.out.println(o); //01540021
So say I have a string called x that = "Hello world". I want to somehow make it so that it will flip those two words and instead display "world Hello". I am not very good with loops or arrays and obviously am a beginner. Could I accomplish this somehow by splitting my string? If so, how? If not, how could I do this? Help would be appreciated, thanks!
1) split string into String array on space.
String myArray[] = x.split(" ");
2) Create new string with words in reverse order from array.
String newString = myArray[1] + " " + myArray[0];
Bonus points for using a StringBuilder instead of concatenation.
String abc = "Hello world";
String cba = abc.replace( "Hello world", "world Hello" );
abc = "This is a longer string. Hello world. My String";
cba = abc.replace( "Hello world", "world Hello" );
If you want, you can explode your string as well:
String[] pieces = abc.split(" ");
for( int i=0; i<pieces.length-1; ++i )
if( pieces[i]=="Hello" && pieces[i+1]=="world" ) swap(pieces[i], pieces[i+1]);
There are many other ways you can do it too. Be careful for capitalization. You can use .toUpperCase() in your if statements and then make your matching conditionals uppercase, but leave the results with their original capitalization, etc.
Here's the solution:
import java.util.*;
public class ReverseWords {
public String reverseWords(String phrase) {
List<String> wordList = Arrays.asList(phrase.split("[ ]"));
Collections.reverse(wordList);
StringBuilder sbReverseString = new StringBuilder();
for(String word: wordList) {
sbReverseString.append(word + " ");
}
return sbReverseString.substring(0, sbReverseString.length() - 1);
}
}
The above solution was coded by me, for Google Code Jam and is also blogged here: Reverse Words - GCJ 2010
Just use this method, call it and pass the string that you want to split out
static String reverseWords(String str) {
// Specifying the pattern to be searched
Pattern pattern = Pattern.compile("\\s");
// splitting String str with a pattern
// (i.e )splitting the string whenever their
// is whitespace and store in temp array.
String[] temp = pattern.split(str);
String result = "";
// Iterate over the temp array and store
// the string in reverse order.
for (int i = 0; i < temp.length; i++) {
if (i == temp.length - 1) {
result = temp[i] + result;
} else {
result = " " + temp[i] + result;
}
}
return result;
}
Depending on your exact requirements, you may want to split on other forms of whitespace (tabs, multiple spaces, etc.):
static Pattern p = Pattern.compile("(\\S+)(\\s+)(\\S+)");
public String flipWords(String in)
{
Matcher m = p.matcher(in);
if (m.matches()) {
// reverse the groups we found
return m.group(3) + m.group(2) + m.group(1);
} else {
return in;
}
}
If you want to get more complex see the docs for Pattern http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
Try something as follows:
String input = "how is this";
List<String> words = Arrays.asList(input.split(" "));
Collections.reverse(words);
String result = "";
for(String word : words) {
if(!result.isEmpty()) {
result += " ";
}
result += word;
}
System.out.println(result);
Output:
this is how
Too much?
private static final Pattern WORD = Pattern.compile("^(\\p{L}+)");
private static final Pattern NUMBER = Pattern.compile("^(\\p{N}+)");
private static final Pattern SPACE = Pattern.compile("^(\\p{Z}+)");
public static String reverseWords(final String text) {
final StringBuilder sb = new StringBuilder(text.length());
final Matcher wordMatcher = WORD.matcher(text);
final Matcher numberMatcher = NUMBER.matcher(text);
final Matcher spaceMatcher = SPACE.matcher(text);
int offset = 0;
while (offset < text.length()) {
wordMatcher.region(offset, text.length());
numberMatcher.region(offset, text.length());
spaceMatcher.region(offset, text.length());
if (wordMatcher.find()) {
final String word = wordMatcher.group();
sb.insert(0, reverseCamelCase(word));
offset = wordMatcher.end();
} else if (numberMatcher.find()) {
sb.insert(0, numberMatcher.group());
offset = numberMatcher.end();
} else if (spaceMatcher.find()) {
sb.insert(0, spaceMatcher.group(0));
offset = spaceMatcher.end();
} else {
sb.insert(0, text.charAt(offset++));
}
}
return sb.toString();
}
private static final Pattern CASE_REVERSAL = Pattern
.compile("(\\p{Lu})(\\p{Ll}*)(\\p{Ll})$");
private static String reverseCamelCase(final String word) {
final StringBuilder sb = new StringBuilder(word.length());
final Matcher caseReversalMatcher = CASE_REVERSAL.matcher(word);
int wordEndOffset = word.length();
while (wordEndOffset > 0 && caseReversalMatcher.find()) {
sb.insert(0, caseReversalMatcher.group(3).toUpperCase());
sb.insert(0, caseReversalMatcher.group(2));
sb.insert(0, caseReversalMatcher.group(1).toLowerCase());
wordEndOffset = caseReversalMatcher.start();
caseReversalMatcher.region(0, wordEndOffset);
}
sb.insert(0, word.substring(0, wordEndOffset));
return sb.toString();
}
Is it possible to make String.replaceAll put the number (count) of the current replacement into the replacement being made?
So that "qqq".replaceAll("(q)", "something:$1 ") would result in "1:q 2:q 3:q"?
Is there anything that I can replace something in the code above with, to make it resolve into the current substitution count?
Here is one way of doing this:
StringBuffer resultString = new StringBuffer();
String subjectString = new String("qqqq");
Pattern regex = Pattern.compile("q");
Matcher regexMatcher = regex.matcher(subjectString);
int i = 1;
while (regexMatcher.find()) {
regexMatcher.appendReplacement(resultString, i+":"+regexMatcher.group(1)+" ");
i++;
}
regexMatcher.appendTail(resultString);
System.out.println(resultString);
See it
No, not with the replaceAll method. The only backreference is \n where n is the n'th capturing group matched.
For this you have to create your own replaceAll() method.
This helps you:
public class StartTheClass
{
public static void main(String[] args)
{
String string="wwwwww";
System.out.println("Replaced As: \n"+replaceCharector(string, "ali:", 'w'));
}
public static String replaceCharector(String original, String replacedWith, char toReplaceChar)
{
int count=0;
String str = "";
for(int i =0; i < original.length(); i++)
{
if(original.charAt(i) == toReplaceChar)
{
str += replacedWith+(count++)+" ";//here add the 'count' value and some space;
}
else
{
str += original.charAt(i);
}
}
return str;
}
}
The output I got is:
Replaced As:
ali:0 ali:1 ali:2 ali:3 ali:4 ali:5