Finding Pattern from one string to apply to another string - Java - java

So I have a string like this: <em>1234</em>56.70
it's basically a number where the em tags help identify what to highlight in the string
I need to first convert the string to an actual number with the current locale format. So I remove the em tags (replaceAll by emptyString) and then use the numberFormat java API to get a string like: $123,456.70
The problem with this is, I lost the highlight (em) tags. So I need to put it back in the string that is formatted, something like this: <em>$123,4</em>56.70
highlightValue = "<em>1234</em>56.70";
highlightValue = highlightValue.replaceAll("<em>", "").replaceAll("</em>", ""); // highlightValue is now 123456.70
highlightValue = numberFormat.convertToFormat(highlightValue, currencyCode); // highlightValue is now $123,456.70
highlightValue = someFunction(highlightValue); // this function needs to return <em>$123,4</em>56.70
I am not sure what approach to use. I was trying pattern matching but didn't know how to achieve it.
All help appreciated !

I am assuming that you want to highlight the number from starting up to some number of digits.This can be done.
In the initial string count the number of digits after which the tag is present. The starting tag will always be placed at the beginning. It is the ending tag you have to worry about. Now count the number of digits, excluding any other symbols.When the required number of digits have been passed, again place the tag. Either you can create a StringBuilder from the String highlighted and insert the tag string directly, or divide the string into two substrings and then join them together with the tag string in the middle.
Hope this helped.

I took an approach, where I count the numbers in front of the tag, in the middle of the tag - as I think no formatting will actually change the numbers(assuming you don't add leading zeroes) and after that I insert back the tag based on the numbers which were in front of the tag or for the closing tag in front and inside
so this is the code:
public static void main(String[] args) {
String input1 = "<em>1234</em>56.70";
String result1 = formatString(input1, "em");
System.out.printf("input1 = %s%n", input1);
System.out.printf("result1 = %s%n", result1);
String input2 = "<em>8127</em>29.12";
String result2 = formatString(input2, "em");
System.out.printf("input2 = %s%n", input2);
System.out.printf("result2 = %s%n", result2);
}
private static String formatString(String input, String tagName) {
String tagOpening = String.format("<%s>", tagName);
int tagOpeningLength = tagOpening.length();
String tagClosing = String.format("</%s>", tagName);
int tagClosingLength = tagClosing.length();
int inputLength = input.length();
int tagOpeningPos = input.indexOf(tagOpening);
int tagClosingPos = input.indexOf(tagClosing, tagOpeningPos);
String beforeTag;
if(tagOpeningPos > 0)
beforeTag = input.substring(0, tagOpeningPos);
else
beforeTag = "";
int digitsInBeforeTag = countNumbers(beforeTag);
String tagValue;
if(tagOpeningPos + tagOpeningLength < tagClosingPos)
tagValue = input.substring(tagOpeningPos + tagOpeningLength, tagClosingPos);
else
tagValue = "";
int digitsInTagValue = countNumbers(tagValue);
String afterTag;
if((tagClosingPos + tagClosingLength) < inputLength)
afterTag = input.substring(tagClosingPos + tagClosingLength);
else
afterTag = "";
String valueToBeFormatted = beforeTag + tagValue + afterTag;
double value = Double.parseDouble(valueToBeFormatted);
NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
String formattedValue = nf.format(value);
int newEmOpeningPos = findSubstringWithThisManyNumbers(formattedValue, digitsInBeforeTag);
int newEmClosingPos = findSubstringWithThisManyNumbers(formattedValue, digitsInBeforeTag+digitsInTagValue);
StringBuilder result = new StringBuilder();
result.append(formattedValue.substring(0, newEmOpeningPos));
result.append(tagOpening);
result.append(formattedValue.substring(newEmOpeningPos, newEmClosingPos));
result.append(tagClosing);
result.append(formattedValue.substring(newEmClosingPos));
return result.toString();
}
private static int findSubstringWithThisManyNumbers(String input, int digitCount) {
int pos = 0;
int counter = 0;
for(char c : input.toCharArray()) {
if(counter >= digitCount)
break;
if(Character.isDigit(c))
counter++;
pos++;
}
return pos;
}
private static int countNumbers(String str) {
int result = 0;
for(char c : str.toCharArray())
if(Character.isDigit(c))
result++;
return result;
}
the output was
input1 = <em>1234</em>56.70
result1 = <em>123,4</em>56.7
input2 = <em>8127</em>29.12
result2 = <em>812,7</em>29.12

I don't know how can this be practical. But anyway.
String highlightValue = "0<em>1234</em>56.70";
int startIndex = highlightValue.indexOf("<em>");
String startString = highlightValue.substring(0, startIndex);
String endString = highlightValue.substring(highlightValue.indexOf("</em>") + "</em>".length());
highlightValue = highlightValue.replaceAll("<em>", "").replaceAll("</em>", "");
highlightValue = numberFormat.convertToFormat(highlightValue, currencyCode);
// highlightValue is now $123,456.70
int endIndex = highlightValue.indexOf(endString);
highlightValue = startString + "<em>" + highlightValue.substring(0, endIndex) + "</em>" + endString;
System.out.println(highlightValue);
// 0<em>$123,4</em>56.70

Related

Replace part of substring with specific characters based on delimiter

String s = "abc//jason:1234567#123.123.213.212/";
I want to replace all the substring before and after ":" delimiter with "......."
I want my final output to be :
"abc//.....:.......#123.123.213:212/"
I tried doing this since there is a second : in the string it gets messed up, is it there better way to be able to get my output:
String [] headersplit;
headersplit = s.split(":");
If you want to locate only symbols between "//" and "#" then algorithm is simple, provided that mention symbols are compulsory.
public class Main {
public static void main(String[] args) {
String s = "abc//jason:1234567#123.123.213.212/";
System.out.println(replaceSensitiveInfo(s));
}
static String replaceSensitiveInfo(String src) {
int slashes = src.indexOf("//");
int colon = src.indexOf(":", slashes);
int at = src.indexOf("#", colon);
StringBuilder sb = new StringBuilder(src);
sb.replace(slashes + 2, colon, ".".repeat(colon - slashes - 2));
sb.replace(colon + 1, at, ".".repeat(at - colon - 1));
return sb.toString();
}
}
Not the best way but it works for your example and should work for others:
String s = "abc//jason:1234567#123.123.213:212/";
String result = replaceSensitiveInfo(s);
private String replaceSensitiveInfo(String info){
StringBuilder sb = new StringBuilder(info);
String substitute = ".";
int start = sb.indexOf("//") + 2;
int end = sb.indexOf(":");
String firstReplace = substitute.repeat(end - start);
sb.replace(start, end, firstReplace);
int start2 = sb.indexOf(":") + 1;
int end2 = sb.indexOf("#");
String secondReplace = substitute.repeat(end2 - start2);
sb.replace(start2, end2, secondReplace);
return sb.toString();
}

Split String from the last iteration

This post is an update to this one : get specific character in a string with regex and remove unused zero
In the first place, i wanted to remove with an regular expression the unused zero in the last match.
I found that the regular expression is a bit overkill for what i need.
Here is what i would like now,
I would like to use split() method
to get from this :
String myString = "2020-LI50532-3329-00100"
this :
String data1 = "2020"
String data2 = "LI50532"
String data3 = "3329"
String data4 = "00100"
So then i can remove from the LAST data the unused Zero
to convert "00100" in "100"
And then concatenate all the data to get this
"2020-LI50532-3329-100"
Im not familiar with the split method, if anyone can enlight me about this ^^
You can use substring method to get rid of the leading zeros...
String myString = "2020-LI50532-3329-00100";
String[] data = myString.split("-");
data[3] = data[3].substring(2);
StringBuilder sb = new StringBuilder();
sb.append(data[0] + "-" + data[1] + "-" + data[2] + "-" + data[3]);
String result = sb.toString();
System.out.println(result);
Assuming that we want to remove the leading zeroes of ONLY the last block, maybe we can:
Extract the last block
Convert it to Integer and back to String to remove leading zeroes
Replace the last block with the String obtained in above step
Something like this:
public String removeLeadingZeroesFromLastBlock(String text) {
int indexOfLastDelimiter = text.lastIndexOf('-');
if (indexOfLastDelimiter >= 0) {
String lastBlock = text.substring(indexOfLastDelimiter + 1);
String lastBlockWithoutLeadingZeroes = String.valueOf(Integer.valueOf(lastBlock)); // will throw exception if last block is not an int
return text.substring(0, indexOfLastDelimiter + 1).concat(lastBlockWithoutLeadingZeroes);
}
return text;
}
Solution using regex:
public class Main {
public static void main(String[] args) {
// Test
System.out.println(parse("2020-LI50532-3329-00100"));
System.out.println(parse("2020-LI50532-3329-00001"));
System.out.println(parse("2020-LI50532-03329-00100"));
System.out.println(parse("2020-LI50532-03329-00001"));
}
static String parse(String str) {
return str.replaceAll("0+(?=[1-9]\\d*$)", "");
}
}
Output:
2020-LI50532-3329-100
2020-LI50532-3329-1
2020-LI50532-03329-100
2020-LI50532-03329-1
Explanation of the regex:
One or more zeros followed by a non-zero digit which can be optionally followed by any digit(s) until the end of the string (specified by $).
Solution without using regex:
You can do it also by using Integer.parseInt which can parse a string like 00100 into 100.
public class Main {
public static void main(String[] args) {
// Test
System.out.println(parse("2020-LI50532-3329-00100"));
System.out.println(parse("2020-LI50532-3329-00001"));
System.out.println(parse("2020-LI50532-03329-00100"));
System.out.println(parse("2020-LI50532-03329-00001"));
}
static String parse(String str) {
String[] parts = str.split("-");
try {
parts[parts.length - 1] = String.valueOf(Integer.parseInt(parts[parts.length - 1]));
} catch (NumberFormatException e) {
// Do nothing
}
return String.join("-", parts);
}
}
Output:
2020-LI50532-3329-100
2020-LI50532-3329-1
2020-LI50532-03329-100
2020-LI50532-03329-1
you can convert the last string portion to integer type like below for removing unused zeros:
String myString = "2020-LI50532-3329-00100";
String[] data = myString.split("-");
data[3] = data[3].substring(2);
StringBuilder sb = new StringBuilder();
sb.append(data[0] + "-" + data[1] + "-" + data[2] + "-" + Integer.parseInt(data[3]));
String result = sb.toString();
System.out.println(result);
You should avoid String manipulation where possible and rely on existing types in the Java language. One such type is the Integer. It looks like your code consists of 4 parts - Year (Integer) - String - Integer - Integer.
So to properly validate it I would use the following code:
Scanner scan = new Scanner("2020-LI50532-3329-00100");
scan.useDelimiter("-");
Integer firstPart = scan.nextInt();
String secondPart = scan.next();
Integer thirdPart = scan.nextInt();
Integer fourthPart = scan.nextInt();
Or alternatively something like:
String str = "00100";
int num = Integer.parseInt(str);
System.out.println(num);
If you want to reconstruct your original value, you should probably use a NumberFormat to add the missing 0s.
The main points are:
Always try to reuse existing code and tools available in your language
Always try to use available types (LocalDate, Integer, Long)
Create your own types (classes) and use the expressiveness of the Object Oriented language
public class Test {
public static void main(String[] args) {
System.out.println(trimLeadingZeroesFromLastPart("2020-LI50532-03329-00100"));
}
private static String trimLeadingZeroesFromLastPart(String input) {
String delem = "-";
String result = "";
if (input != null && !input.isEmpty()) {
String[] data = input.split(delem);
StringBuilder tempStrBldr = new StringBuilder();
for (int idx = 0; idx < data.length; idx++) {
if (idx == data.length - 1) {
tempStrBldr.append(trimLeadingZeroes(data[idx]));
} else {
tempStrBldr.append(data[idx]);
}
tempStrBldr.append(delem);
}
result = tempStrBldr.substring(0, tempStrBldr.length() - 1);
}
return result;
}
private static String trimLeadingZeroes(String input) {
int idx;
for (idx = 0; idx < input.length() - 1; idx++) {
if (input.charAt(idx) != '0') {
break;
}
}
return input.substring(idx);
}
}
Output:
2020-LI50532-3329-100

Splitting String based on nth Occurence of a String in Java

How to Split a String based on the nth(Ex: second) occurence of a delimiter.whereas other than the nth occurence ,all other delimiters should be retained
I/P:
String name="This is my First Line";
int delimiter=" ";
int count=3;//This is a dynamic value
O/P:
String firstpart=This is my
String Secondpart=First Line
Due to limitations with regex, you can't split it in 1 line of code, but you can do it in 2 lines:
String firstPart = name.replaceAll("^((.*?" + delimiter + "){" + count + "}).*", "$1");
String secondPart = name.replaceAll("^(.*?" + delimiter + "){" + count + "}(.*)", "$2");
I got it like this
String name="This is my First Line";
int count=3;
String s1,s2;
String arr[]=name.split();//default will be space
for(i=0;i<arr.length;i++)
if(i<count)
s1=s1+arr[i]+" "
else
s2=s2+arr[i]+" "
Just use indexOf to search for the delimiter and repeat that until you found it count-times. Here is a snippet:
String name = "This is my First Line";
String delimiter = " ";
int count = 3;
// Repeativly search for the delimiter
int lastIndex = -1;
for (int i = 0; i < count; i++) {
// Begin to search from the position after the last matching index
lastIndex = name.indexOf(delimiter, lastIndex + 1);
// Could not be found
if (lastIndex == -1) {
break;
}
}
// Get the result
if (lastIndex == -1) {
System.out.println("Not found!");
} else {
// Use the index to split
String before = name.substring(0, lastIndex);
String after = name.substring(lastIndex);
// Print the results
System.out.println(before);
System.out.println(after);
}
It will now output
This is my
First Line
Note the whitespace (the delimiter) at the beginning of the last line, you can omit this if you want by using the following code at the end
// Remove the delimiter from the beginning of 'after'
String after = ...
after = after.subString(delimiter.length());
static class FindNthOccurrence
{
String delimiter;
public FindNthOccurrence(String del)
{
this.delimiter = del;
}
public int findAfter(String findIn, int findOccurence)
{
int findIndex = 0;
for (int i = 0; i < findOccurence; i++)
{
findIndex = findIn.indexOf(delimiter, findIndex);
if (findIndex == -1)
{
return -1;
}
}
return findIndex;
}
}
FindNthOccurrence nth = new FindNthOccurrence(" ");
String string = "This is my First Line";
int index = nth.nthOccurrence(string, 2);
String firstPart = string.substring(0, index);
String secondPart = string.substring(index+1);
Simply like this,
Tested and work perfectly in Java 8
public String[] split(String input,int at){
String[] out = new String[2];
String p = String.format("((?:[^/]*/){%s}[^/]*)/(.*)",at);
Pattern pat = Pattern.compile(p);
Matcher matcher = pat.matcher(input);
if (matcher.matches()) {
out[0] = matcher.group(1);// left
out[1] = matcher.group(2);// right
}
return out;
}
//Ex: D:/folder1/folder2/folder3/file1.txt
//if at = 2, group(1) = D:/folder1/folder2 and group(2) = folder3/file1.txt

How to flip two words in a string, Java

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();
}

remove the last part of a string in java

String Y="part1 part2 part3",X="part1";
boolean foundMatch = false;
while(!foundMatch) {
foundMatch = Y.equals(X);
if(foundMatch) {
break;
}
else {
Y = useSplitToRemoveLastPart(Y);
if(Y.equals("")) {
break;
}
}
//implementation of useSplitToRemoveLastPart()
private static String useSplitToRemoveLastPart(String y) {
//What goes here .. It should chop the last part of the string..
return null;
}
Can anyone help ...
If you want part3 to be removed and provided that all the words are separated by space
String str ="part1 part2 part3";
String result = str.substring(0,str.lastIndexOf(" "));
If you really want to use split:
private static String useSplitToRemoveLastPart(String str) {
String[] arr = str.split(" ");
String result = "";
if (arr.length > 0) {
result = str.substring(0, str.lastIndexOf(" " + arr[arr.length-1]));
}
return result;
}
Your whole code can be optimized to:
boolean foundmatch = y.startsWith(x);
y = foundmatch? x : "";
public String removeLastSubstring(String target, String toRemove){
int idx = target.lastIndexOf(toRemove);
target = target.substring(0, idx) + target.substring(idx + toRemove.length());
return target;
}
You only need to pass it your target and the LAST substring you want to remove, example:
String s = "123 #abc# 456";
s = removeLastSubstring(s, "#abc#");
If you want to do it using split, then you can do:
String s[] = Y.split(" ");
String n = "";
for (int i = 0; i < s.length - 1; i++)
n+= s[i];
return n;
By the way, If the method you need to build is called useSplitToRemoveLastPart(String t), then I'd suggest you to use split to remove last part.
Take a look here.

Categories

Resources