I would like to split these strings:
/d/{?a}
/a/b/{c}{?d}
/a/b/c{?d}
into following list of segments:
[d, {?a}] (this case is easy, just split using /)
[a, b, {c}, {?d}]
[a, b, c, {?d}]
For the other cases, splitting using / will not get the result that I wanted. In which case, the last string element of 2. and 3. will be {c}{?d} and c{?d}.
What is the best approach to achieve all 1,2,3 at the same time?
Thanks.
try to solve the problem with a regex. This might be a script to start with:
String regex = "(/)|(?=\\{)";
String s = "/a/b/{c}{?d}";
String[] split = s.split(regex);
you will get empty elements in the split array with this regex, but all other elements are splitted correctly
Here is some simple way of solving it in case you know your input is always going to be either any chars xyz different than { and } or {xyz}. In case you could have any other input, this would require some modifications:
String[] arr = input.split("/");
List<String> result = new ArrayList<>();
for (String elem : arr) {
int lastCut = 0;
for (int i = 0; i < elem.length(); i++) {
if (elem.charAt(i) == '{' || elem.charAt(i) == '}') {
if (i > 0) {
String previousElem = elem.substring(lastCut, i);
result.add(previousElem);
}
lastCut = i;
}
}
if (lastCut < elem.length() - 2)
String lastElem = elem.substring(lastCut + 1, elem.length());
result.add(lastElem);
}
In the first case it's splitting. But in the rest cases it's parsing.
You have to parse a string first and then split it. Try to add '/' right before every '{' and after every '}'. And then you can split it by '/'.
E.g.:
Before parsing:
2. /a/b/{c}{?d}
3. /a/b/c{?d}
After parsing:
2. /a/b//{c}//{?d}/
3. /a/b/c/{?d}/
Then remove excessive '/', split the string and be happy.
Related
I have a list of alphanumeric strings as below
["nG5wnyPVNxS6PbbDNNbRsK5zanG94Et6Q4y74","GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1odeNv","GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1o12NN"]
I need to mask all elements with last 4 characters visible and [ " must not be masked as below.
["XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4y74","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXdeNv","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX12NN"]
I have tried using
(\\W+)(\\W+)(\\w+)(\\w+)(\\w+)(\\w+)(\\w+)(\\W+)(\\W+)
as the key and $1$2XXXXXXXXXX$4$5$6$7$8$9 as the value in
maskedValue = maskedValue.replaceAll("(\\W+)(\\W+)(\\w+)(\\w+)(\\w+)(\\w+)(\\w+)(\\W+)(\\W+)", "$1$2XXXXXXXXXX$4$5$6$7$8$9")
but this only masked the first element.
["XXXXXXXXXXdeNv","nG5wnyPVNxS6PbbDNNbRsK5zanG94Et6Q4y74"]
Any leads are appreciated. Thanks in advance.
For a single value, you could use an assertion to match a word character asserting 4 characters at the end of the string.
\w(?=\w*\w{4}$)
Regex demo | Java demo
String values[] = {"nG5wnyPVNxS6PbbDNNbRsK5zanG94Et6Q4y74","GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1odeNv","GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1o12NN"};
for (String element : values)
System.out.println(element.replaceAll("\\w(?=\\w*\\w{4}$)", "X"));
Output
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4y74
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXdeNv
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX12NN
For the whole string, you might use a finite quantifier in a positive lookbehind to match the opening " followed by a number of word characters. Then match all the characters that have 4 character before the closing "
"(?<=\"{0,100})\\w(?=\\w*\\w{4}\")"
Regex demo | Java demo
String regex = "(?<=\"{0,100})\\w(?=\\w*\\w{4}\")";
String string = "[\"nG5wnyPVNxS6PbbDNNbRsK5zanG94Et6Q4y74\",\"GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1odeNv\",\"GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1o12NN\"] ";
System.out.println(string.replaceAll(regex, "X"));
Output
["XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX4y74","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXdeNv","XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX12NN"]
Using a stream:
List<String> terms = Arrays.asList(new String[] {
"nG5wnyPVNxS6PbbDNNbRsK5zanG94Et6Q4y74",
"GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1odeNv",
"GgQoDWqP7KtxXeePyyebu5EnNp8XxPC1o12NN"
});
List<String> termsOut = terms.stream()
.map(t -> String.join("", Collections.nCopies(t.length() - 4, "x")) +
t.substring(t.length() - 4))
.collect(Collectors.toList());
System.out.println(termsOut);
This prints:
[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4y74,
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdeNv,
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx12NN]
Note that this solution does not even use regex, which means it may outperform a regex based solution.
Assuming each of these strings will start and end with quotes
Algo:
Use a flag or stack data structure to know if it's a starting quote or ending quote.
For example:
Traverse the string. Initially flag will be false. When you encounter a new quote you have to flip flag and keep traversing till you find other quote. You can do the same with
Stack stack = new Stack<>();
Sample workflow:
String str="random";
boolean flag = false;
int idx = 0;
List<Pair<Integer, Integer>> indices = new ArrayList<>();
StringBuilder string = new StringBuilder(); // for final string
int start;
int end;
while(idx < str.length()){
if (str.charAt(idx) == '"' && !flag){
// start index of string
string.append(s.charAt(idx));
start = idx;
flag = true;
}
else if (str.charAt(idx) == '"' && !flag){
// end index of string
flag = false;
end = idx;
char[] mask = new char[end-3-start];
Arrays.fill(mask, 'x');
string.append(new String(mask)); // need to put 'x' in place
}
if (!flag){
string.append(s.charAt(idx));
}
idx++;
}
Complexity: O(n)
I am struggling with how to actually do this. Say I have this string
"This Str1ng i5 fun"
I want to replace the '1' with "One" and the 5 with "Five"
"This StrOneng iFive fun"
I have tried to loop thorough the string and manually replace them, but the count is off. I have also tried to use lists, arrays, stringbuilder, etc. but I cannot get it to work:
char[] stringAsCharArray = inputString.toCharArray();
ArrayList<Character> charArraylist = new ArrayList<Character>();
for(char character: stringAsCharArray) {
charArraylist.add(character);
}
int counter = startPosition;
while(counter < endPosition) {
char temp = charArraylist.get(counter);
String tempString = Character.toString(temp);
if(Character.isDigit(temp)){
char[] tempChars = digits.getDigitString(Integer.parseInt(tempString)).toCharArray(); //convert to number
charArraylist.remove(counter);
int addCounter = counter;
for(char character: tempChars) {
charArraylist.add(addCounter, character);
addCounter++;
}
counter += tempChars.length;
endPosition += tempChars.length;
}
counter++;
}
I feel like there has to be a simple way to replace a single character at a string with a substring, without having to do all this iterating. Am I wrong here?
String[][] arr = {{"1", "one"},
{"5", "five"}};
String str = "String5";
for(String[] a: arr) {
str = str.replace(a[0], a[1]);
}
System.out.println(str);
This would help you to replace multiple words with different text.
Alternatively you could use chained replace for doing this, eg :
str.replace(1, "One").replace(5, "five");
Check this much better approach : Java Replacing multiple different substring in a string at once (or in the most efficient way)
You can do
string = string.replace("1", "one");
Don't use replaceAll, because that replaces based on regular expression matches (so that you have to be careful about special characters in the pattern, not a problem here).
Despite the name, replace also replaces all occurrences.
Since Strings are immutable, be sure to assign the result value somewhere.
Try the below:
string = string.replace("1", "one");
string = string.replace("5", "five");
.replace replaces all occurences of the given string with the specified string, and is quite useful.
I've seen many examples, but I am not getting the expected result.
Given a String:
"manikanta, Santhosh, ramakrishna(mani, santhosh), tester"
I would like to get the String array as follows:
manikanta,
Santhosh,
ramakrishna(mani, santhosh),
tester
I tried the following regex (got from another example):
"(\".*?\"|[^\",\\s]+)(?=\\s*,|\\s*$)"
This does this trick:
String[] parts = input.split(", (?![^(]*\\))");
which employs a negative lookahead to assert that the next bracket char is not a close bracket, and produces:
manikanta
Santhosh
ramakrishna(mani, santhosh)
tester
The desired output as per your question keeps the trailing commas, which I assume is an oversight, but if you really do want to keep the commas:
String[] parts = input.split("(?<=,) (?![^(]*\\))");
which produces the same, but with the trailing commas intact:
manikanta,
Santhosh,
ramakrishna(mani, santhosh),
tester
Suppose, we can split with whitespaces (due to your example), then you can try this regex \s+(?=([^\)]*\()|([^\)\(]*$)) like:
String str = "manikanta, Santhosh, ramakrishna(mani, santhosh), ramakrishna(mani, santhosh), tester";
String[] ar = str.split("\\s+(?=([^\\)]*\\()|([^\\)\\(]*$))");
Where:
\s+ any number of whitespaces
(?=...) positive lookahead, means that after current position must be the string, that matches to ([^\\)]*\\() or | to ([^\\)\\(]*$)
([^\\)]*\\() ignores whitespaces inside the ( and )
([^\\)\\(]*$)) all whitespaces, if they are not followed by ( and ), here is used to split a part with the tester word
As I stated in my comment to the question this problem may be impossible to solve by regular expressions.
The following code (java) gives a hint what to do:
private void parse() {
String string = null;
char[] chars = string.toCharArray();
List<String> parts = new ArrayList<String>();
boolean split = true;
int lastEnd = 0;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
switch (c) {
case '(':
split = false;
break;
case ')':
split = true;
break;
}
if (split && c == ',') {
parts.add(string.substring(lastEnd, i - 1));
lastEnd = i++;
}
}
}
Note that the code lacks some checks for constraints (provided string is null, array borders, ...).
My app reads a value of a NFC tag which contains plain text, to then cut the read String up.
The string should be as follow:
"r=v;b=v;g=v;n=v;p=v;m=v;s=v"
I want to read the "v" characters, since they are divided by the ; character, and i remember there being a function that let me divide strings like this, how do i do it? The v value isn't constant, it could span 1 position like it could span 3 or 4. The app is for Android phones, written in Java on Android Studio.
You are asking about String method .split()
it's splits string into array and so for you question, since split can work with regex you can split exactly for needed patterns
like this:
String givenString="r=v;b=v;g=v;n=v;p=v;m=v;s=v";
String[]vs=givenString.split("([;]?[a-z]{1}[=])");
for(String v: vs){System.out.println(v);}//prints all v
Regex explanation:
[;]? -> means may start with one semicolon or none
[a-z]{1} -> means one letter lower case only
[=] -> means equals sign
Edit: if you use split by only semicolon (as #cvester suggested), you get the whole entry string, such as: "r=v","b=v", etc..
in this case you can iterate over all entries and then make one more split by equals "=" like this:
String []entries=givenString.split(";");
for (String entry:entries){
String []vs=entry.split("=");
System.out.println(vs[1]);//prints all v
}
Java has a split function on a String.
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split(java.lang.String)
So you can just use split(";");
Use String#split() or you could create your own logic.
String string = "r=v;b=asfasv;g=v;n=asf;p=v;m=v;s=vassaf";
String word = "";
int i = 0;
ArrayList<String> list = new ArrayList();
while(i < string.length())
{
if(string.charAt(i) == '=')
{
i++;
while( i < string.length() && string.charAt(i) != ';' )
{
word += string.charAt(i);
i++;
}
list.add(word);
System.out.println(word);
word = "";
}
i ++;
}
if(!word.equals(""))
list.add(word);
System.out.println(list);
You could use regex to avoid looping
String input = "r=v;b=v;g=v;n=v;p=v;m=v;s=v";
input.trim().replaceAll("([a-zA-Z]=)+","").replaceAll(";",""));
I need to split a string based on delimiters and assign it to an object. I am aware of the split function, but I am unable to figure how to do it for my particular string.
The object is of the format:
class Selections{
int n;
ArrayList<Integer> choices;
}
The string is of the form :
1:[1,3,2],2:[1],3:[4,3],4:[4,3]
where:
1:[1,3,2] is an object with n=1 and Arraylist should have numbers 1,2,3.
2:[1] is an object with n=2 and Arraylist should have number 1
and so on .
I cannot use split with "," as delimiter because both individual objects and the elements within [] are separated by ",".
Any ideas would be appreciated.
You could use a regex to have a more robust result as follows:
String s = "1:[1,3,2],2:[1],3:[4,3],4:[4,3],5:[123,53,1231],123:[54,98,434]";
// commented one handles white spaces correctly
//Pattern p = Pattern.compile("[\\d]*\\s*:\\s*\\[((\\d*)(\\s*|\\s*,\\s*))*\\]");
Pattern p = Pattern.compile("[\\d]*:\\[((\\d*)(|,))*\\]");
Matcher matcher = p.matcher(s);
while (matcher.find())
System.out.println(matcher.group());
The regex can probably be tuned to be more accurate (e.g., handling white spaces) but it works fine on the example.
How about using "]," as delimiter?
If your structure is strictly like you said, it should be able to identify and split.
(Sorry, I want to leave it as comment, but my reputation does not allow)
You will need to perform multiple splits.
Split with the delimiter "]," (as mentioned in other comments and answers).
For each of the resulting strings, split with the delimiter ":[".
you will need to cleanup the last entry (from the split in step 1), because it will end with ']'
I have no idea how to use a build-in function for this. I would just write my own split method:
private List<Sections> split(String s){
private List<Sections> sections = new ArrayList<>();
private boolean insideBracket = false;
private int n = 0;
private List<Integer> ints = new ArrayList<>();
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if(!insideBracket && !c.equals(':')){
n = c.getNumericValue();
} else if(c.equals('[')){
insideBracket = true;
} else if (c.equals(']')){
insideBracket = false;
sections.add(new Section(n, ints));
ints = new ArrayList();
} else if(insideBracket && !c.equals(',')){
ints.add(c.getNumericValue());
}
}
}
you probably need to modify that a little bit. Right now it dont works if a number has multiple digits.
Try this
while(true){
int tmp=str.indexOf("]")+1;
System.out.println(str.substring(0,tmp));
if(tmp==str.length())
break;
str=str.substring(tmp+1);
}