How to insert char at specific location throughout the string? [duplicate] - java

I'm getting in an int with a 6 digit value. I want to display it as a String with a decimal point (.) at 2 digits from the end of int. I wanted to use a float but was suggested to use String for a better display output (instead of 1234.5 will be 1234.50). Therefore, I need a function that will take an int as parameter and return the properly formatted String with a decimal point 2 digits from the end.
Say:
int j= 123456
Integer.toString(j);
//processing...
//output : 1234.56

As mentioned in comments, a StringBuilder is probably a faster implementation than using a StringBuffer. As mentioned in the Java docs:
This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
Usage :
String str = Integer.toString(j);
str = new StringBuilder(str).insert(str.length()-2, ".").toString();
Or if you need synchronization use the StringBuffer with similar usage :
String str = Integer.toString(j);
str = new StringBuffer(str).insert(str.length()-2, ".").toString();

int j = 123456;
String x = Integer.toString(j);
x = x.substring(0, 4) + "." + x.substring(4, x.length());

int yourInteger = 123450;
String s = String.format("%6.2f", yourInteger / 100.0);
System.out.println(s);

Using ApacheCommons3 StringUtils, you could also do
int j = 123456;
String s = Integer.toString(j);
int pos = s.length()-2;
s = StringUtils.overlay(s,".", pos, pos);
it's basically substring concatenation but shorter if you don't mind using libraries, or already depending on StringUtils

In most use-cases, using a StringBuilder (as already answered) is a good way to do this. However, if performance matters, this may be a good alternative.
/**
* Insert the 'insert' String at the index 'position' into the 'target' String.
*
* ````
* insertAt("AC", 0, "") -> "AC"
* insertAt("AC", 1, "xxx") -> "AxxxC"
* insertAt("AB", 2, "C") -> "ABC
* ````
*/
public static String insertAt(final String target, final int position, final String insert) {
final int targetLen = target.length();
if (position < 0 || position > targetLen) {
throw new IllegalArgumentException("position=" + position);
}
if (insert.isEmpty()) {
return target;
}
if (position == 0) {
return insert.concat(target);
} else if (position == targetLen) {
return target.concat(insert);
}
final int insertLen = insert.length();
final char[] buffer = new char[targetLen + insertLen];
target.getChars(0, position, buffer, 0);
insert.getChars(0, insertLen, buffer, position);
target.getChars(position, targetLen, buffer, position + insertLen);
return new String(buffer);
}

For Kotlin dudes ;) from the accepted answer (#MikeThomsen's)
fun String.insert(insertAt: Int, string: String): String {
return this.substring(0, insertAt) + string + this.substring(insertAt, this.length)
}
Test ✅
"ThisTest".insert(insertAt = 4, string = "Is").should.equal("ThisIsTest")

String.format("%0d.%02d", d / 100, d % 100);

You could use
System.out.printf("%4.2f%n", ((float)12345)/100));
As per the comments, 12345/100.0 would be better, as would the use of double instead of float.

If you are using a system where float is expensive (e.g. no FPU) or not allowed (e.g. in accounting) you could use something like this:
for (int i = 1; i < 100000; i *= 2) {
String s = "00" + i;
System.out.println(s.substring(Math.min(2, s.length() - 2), s.length() - 2) + "." + s.substring(s.length() - 2));
}
Otherwise the DecimalFormat is the better solution. (the StringBuilder variant above won't work with small numbers (<100)

I think a simpler and more elegant solution to insert a String in a certain position would be this one-liner:
target.replaceAll("^(.{" + position + "})", "$1" + insert);
For example, to insert a missing : into a time String:
"-0300".replaceAll("^(.{3})", "$1:");
What it does is, matches position characters from the beginning of the string, groups that, and replaces the group with itself ($1) followed by the insert string. Mind the replaceAll, even though there's always one occurrence, because the first parameter must be a regex.
Of course it does not have the same performance as the StringBuilder solution, but I believe the succinctness and elegance as a simple and easier to read one-liner (compared to a huge method) is sufficient for making it the preferred solution in most non performance-critical use-cases.
Note I'm solving the generic problem in the title for documentation reasons, of course if you are dealing with decimal numbers you should use the domain-specific solutions already proposed.

There are good answers here, but with Kotlin extensions addition we can do it even more simply:
val indexWhereInsertIsIntended = 2
val inputString = "2408"
val resultingString = inputString.toCharArray().toMutableList()
.also {
it.add(indexWhereInsertIsIntended, '/')
}.joinToString("")
Result = 24/08
This example shows a card expiry date, and slash (/) is intended at 2nd Index. So the resulting index in this case will have / at 2nd index.
If you want to replace and not add:
val indexWhereInsertIsIntended = 2
val inputString = "2408"
val resultingString = inputString.toCharArray()
.also {
it[indexWhereInsertIsIntended] = '/'
}.joinToString("")
Result = 24/0

public static void main(String[] args) {
char ch='m';
String str="Hello",k=String.valueOf(ch),b,c;
System.out.println(str);
int index=3;
b=str.substring(0,index-1 );
c=str.substring(index-1,str.length());
str=b+k+c;
}

// Create given String and make with size 30
String str = "Hello How Are You";
// Creating StringBuffer Object for right padding
StringBuffer stringBufferRightPad = new StringBuffer(str);
while (stringBufferRightPad.length() < 30) {
stringBufferRightPad.insert(stringBufferRightPad.length(), "*");
}
System.out.println("after Left padding : " + stringBufferRightPad);
System.out.println("after Left padding : " + stringBufferRightPad.toString());
// Creating StringBuffer Object for right padding
StringBuffer stringBufferLeftPad = new StringBuffer(str);
while (stringBufferLeftPad.length() < 30) {
stringBufferLeftPad.insert(0, "*");
}
System.out.println("after Left padding : " + stringBufferLeftPad);
System.out.println("after Left padding : " + stringBufferLeftPad.toString());

Try this :
public String ConvertMessage(String content_sendout){
//use unicode (004E00650077) need to change to hex (&#x004E&#x;0065&#x;0077;) first ;
String resultcontent_sendout = "";
int i = 4;
int lengthwelcomemsg = content_sendout.length()/i;
for(int nadd=0;nadd<lengthwelcomemsg;nadd++){
if(nadd == 0){
resultcontent_sendout = "&#x"+content_sendout.substring(nadd*i, (nadd*i)+i) + ";&#x";
}else if(nadd == lengthwelcomemsg-1){
resultcontent_sendout += content_sendout.substring(nadd*i, (nadd*i)+i) + ";";
}else{
resultcontent_sendout += content_sendout.substring(nadd*i, (nadd*i)+i) + ";&#x";
}
}
return resultcontent_sendout;
}

Related

Swapping Characters in a String in Java

Given the above excerpt from a Java code, I need to modify the code such that it could recursively swap pairs of the content of the string variable, "locationAddress".
Please note that the variable, "locationAddress", contains a string of characters, say, abcdefghij.
I wish to swap "abcdefghij" in pairs such that the result will be "badcfehgji".
Please kindly assist with the necessary modification to the above Java code excerpt to make it recursively swap pairs of characters in the string variable, "locationAddress".
public void format(DataObject dataSource) throws Exception {
String locationAddress = dataSource.getValueAsString("Location-Address").substring(4);
if (dataSource.parameterExists("Location-Address")) {
dataSource.setParameter("Parameter-Type","400");
dataSource.setParameter("Parameter-Value", locationAddress);
}
}
Here is a very simple way to do this using regex replacement in Java:
String input = "abcdefghij";
input = input.replaceAll("(.)(.)", "$2$1");
System.out.println(input);
badcfehgji
The idea is to walk down the string, starting at the beginning, capturing two characters at a time, in two different capture groups. Then, just swap those two captured characters in the replacement.
Here's one solution with StringBuilder:
public static String swapAdjacentPairs(String s) {
StringBuilder sb = new StringBuilder(s);
// divide 2 and then multiply by 2 to handle cases where the string length is odd
// we always want an even string length
// also note the i += 2
for (int i = 0 ; i < (s.length() / 2 * 2) ; i += 2) {
swapAdjacent(sb, i);
}
return sb.toString();
}
private static void swapAdjacent(StringBuilder sb, int index) {
char x = sb.charAt(index);
sb.setCharAt(index, sb.charAt(index + 1));
sb.setCharAt(index + 1, x);
}
Usage:
System.out.println(swapAdjacentPairs("abcdefghi"));
A solution using Stream:
String input = "abcdefghijk";
String swapped = IntStream.range(0, input.length())
.map(i -> i % 2 == 0 ? i == input.length() - 1 ? i : i + 1 : i - 1)
.mapToObj(input::charAt)
.map(String::valueOf)
.collect(Collectors.joining());
System.out.println(swapped); // badcfehgjik
The swapping is driven by the index i. If i is even and there is a next (i+1) character then it's used. If i is odd then the previous (i-1) character is used.

Performance (JAVA) ~ String concatenation in a loop with prepending and appending

I'm having performance issues. Does anyone have a faster/better solution for doing the following:
String main = "";
for (String proposition : propositions) {
if (main.length() == 0) {
main = proposition;
} else {
main = "|(" + proposition + "," + main + ")";
}
}
I know concat and stringbuilder are faster, but i don't see how i can use these methods. Because of the following line of code:
main = "|(" + proposition + "," + main + ")";
Thanks in advance!
So from what I can tell there are 3 problems here:
Values are primarily prepended to the string.
For each value a character is appended.
If only one value is present, nothing should be appended or prepended.
With 2 or more items, the 0th item is handled differently:
0:""
1:"A"
2:"|(B,A)"
3:"|(C,|(B,A))"
It can be made quicker by making a few changes:
Reverse the algorithm, this means the majority of the work involves appending, allowing you to use StringBuilders.
Count the number of closing )'s and append those after the loop is finished.
Special case for 0 or 1 items in the list.
With those changes the algorithm should be able to use a StringBuilder and be a lot quicker.
Attempt at an algorithm:
int length = propositions.size();
if (length == 0) {
main = "";
} else {
StringBuilder sb = new StringBuilder();
int nestingDepth = 0;
// Reverse loop, ignoring 0th element due to special case
for (int i = length - 1; i > 0; i--) {
sb.append("|(").append(propositions.get(i)).append(',');
nestingDepth++;
}
// Append last element due to special casing
sb.append(propositions.get(0));
for (int i = 0; i < nestingDepth; i++) {
sb.append(')');
}
main = sb.toString();
}
I believe this should produce the correct results, but it should give the right idea.
The problem is that you're prepending and appending to the string as you go. String and StringBuilder dont handle this well (and give quadratic performance). But you can use a dequeue which supports insertion at start and end to store all the pieces. Then finally you can join the bits in the dequeue.
ArrayDeque bits = new ArrayDeque();
for (String proposition : propositions) {
if (bits.size() == 0) {
bits.push(proposition);
} else {
// Add prefix
main.offerFirst("|(" + proposition + "," );
// Add suffix
main.push(")");
}
}
StringBuilder sb = new StringBuilder();
for( String s : bits) {
sb.append(s);
}
main = sb.toString();
Assuming this is an array of propositions, you could first sum the length of the String(s) in the array. Add 4 for your additional characters, and subtract 4 because you don't use those separators on the first element. That should be the perfect size for your output (this is optional, because StringBuilder is dynamically sized). Next, construct a StringBuilder. Add the first element. All subsequent elements follow the same pattern, so the loop is simplified with a traditional for. Something like,
int len = Stream.of(propositions).mapToInt(s -> s.length() + 4).sum() - 4;
StringBuilder sb = new StringBuilder(len); // <-- len is optional
sb.append(propositions[0]);
for (int i = 1; i < propositions.length; i++) {
sb.insert(0, ",").insert(0, propositions[i]).insert(0, "|(").append(")");
}
System.out.println(sb);

How do you add a newline character in a string at specific indices?

I have a string:
String testString= "For the time being, programming is a consumer job, assembly line coding is the norm, and what little exciting stuff is being performed is not going to make it compared to the mass-marketed cräp sold by those who think they can surf on the previous half-century's worth of inventions forever"
like this: For the time being, programmi \n........\n.......\n
After each length of 20 characters in this string, I want to put a newline character \n for display in a TextView in Android.
You must have to use regex for achieve your task its fast and efficient. Try below code:-
String str = "....";
String parsedStr = str.replaceAll("(.{20})", "$1\n");
The (.{20}) will capture a group of 20 characters. The $1 in the second will put the content of the group. The \n will be then appended to the 20 characters which have been just matched.
How about something like that?
String s = "...whateverstring...";
for(int i = 0; i < s.length(); i += 20) {
s = new StringBuffer(s).insert(i, "\n").toString();
}
I know there is a technically better solution to use a StringBuffer and the insert method for that class, or even regex, but I'll show you a different algorithmic approach using String#substring:
String s = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
int offset = 0; // each time you add a new character, string has "shifted"
for (int i = 20; i + offset < s.length(); i += 20) {
// take first part of string, add a new line, and then add second part
s = s.substring(0, i + offset) + "\n" + s.substring(i + offset);
offset++;
}
System.out.println(s);
The result is this:
12345678901234567890
12345678901234567890
12345678901234567890
12345678901234567890
12345678901234567890
1234567890123456789
StringBuilder sb = new StringBuilder();
int done = 0;
while( done < s.length() ){
int todo = done + 20 < s.length() ? 20 : s.length() - done;
sb.append( s.substring( done, done + todo ) ).append( '\n' );
done += todo;
}
String result = sb.toString();
This also appends a newline at the end, but you can modify it easily to avoid that.

How to change a random element of an attribute?

I'm trying to select a random element in an attribute, and then reverse the value of that randomly selected element between 0 and n, and then reprint the whole attribute again, with the reversed element shown. The reverse value for 0 is 1, and for 1 is 0 in this case.
Here is what I've attempted:
String whatever = "11111";
int n = whatever.length();
//the UI class generates a random integer number between 0 and n
int p = CS2004.UI(0,n);
if (whatever.charAt(p)=='0') {
+= 1;
} else {
+= 0;
}
I'm lost on the adding the opposite number bit.
I should clarify that this is homework!
Strings are immutable in Java, but you could do
StringBuilder sb = new StringBuilder(whatever);
if (whatever.charAt(p)=='0') {
sb.setCharAt(p, '1');
} else {
sb.setCharAt(p, '0');
}
whatever = sb.toString();
OK, lets give this a try.
Firstly, you will need to change the name of your variable 5 - I don't think you're allowed to start variables with a number (see here)
I'm assuming that by 'attribute' you mean the length of the String? This is probably supposed to be the value of your 5 variable.
So, lets look at some modified code...
String whatever = "11111";
int n = whatever.length();
//the UI class generates a random integer number between 0 and n
int p = CS2004.UI(0,n);
StringBuilder sb = new StringBuilder(whatever);
if (whatever.charAt(p)=='0') {
sb.setCharAt(p, '1');
} else {
sb.setCharAt(p, '0');
}
whatever = sb.toString();
This code will change the value of the character in position p, and then convert it back to a String.
Basic StringBuilder usage with a ternary operator produces what you're looking for:
StringBuilder result = new StringBuilder();
result.append(whatever.substring(0, p));
result.append(whatever.charAt(p) == '0' ? "1" : "0");
result.append(whatever.substring(p + 1, whatever.length()));
System.out.println("Result = " + result.toString());
As others have noted, using the StringBuilder.setCharAt() method produces a more concise answer (with the ternary operator added, this is the shortest answer so far):
StringBuilder result = new StringBuilder(whatever);
result.setCharAt(p, whatever.charAt(p) == '0' ? '1' : '0');
System.out.println("Result = " + result.toString());
Strings in Java are immutable so you need to first convert them to some mutable structure before modifying them.
If you are trying to flip the characters at some position in a code then this code might be of help :
String whatever = "11111";
char[] charArray = whatever.toCharArray();
int n = whatever.length();
//the UI class generates a random integer number between 0 and n
int p = CS2004.UI(0,n);
if (charArray[p]=='0') {
charArray[p] = 1;
} else {
charArray[p] = 0;
}
Then you can modify whatever characters you wish to. Once you are done you can reconstruct a String from the charArray as follows :
String result = new String(charArray);
This can also be achieved using StringBuilder.

Split string to equal length substrings in Java

How to split the string "Thequickbrownfoxjumps" to substrings of equal size in Java.
Eg. "Thequickbrownfoxjumps" of 4 equal size should give the output.
["Theq","uick","brow","nfox","jump","s"]
Similar Question:
Split string into equal-length substrings in Scala
Here's the regex one-liner version:
System.out.println(Arrays.toString(
"Thequickbrownfoxjumps".split("(?<=\\G.{4})")
));
\G is a zero-width assertion that matches the position where the previous match ended. If there was no previous match, it matches the beginning of the input, the same as \A. The enclosing lookbehind matches the position that's four characters along from the end of the last match.
Both lookbehind and \G are advanced regex features, not supported by all flavors. Furthermore, \G is not implemented consistently across the flavors that do support it. This trick will work (for example) in Java, Perl, .NET and JGSoft, but not in PHP (PCRE), Ruby 1.9+ or TextMate (both Oniguruma). JavaScript's /y (sticky flag) isn't as flexible as \G, and couldn't be used this way even if JS did support lookbehind.
I should mention that I don't necessarily recommend this solution if you have other options. The non-regex solutions in the other answers may be longer, but they're also self-documenting; this one's just about the opposite of that. ;)
Also, this doesn't work in Android, which doesn't support the use of \G in lookbehinds.
Well, it's fairly easy to do this with simple arithmetic and string operations:
public static List<String> splitEqually(String text, int size) {
// Give the list the right capacity to start with. You could use an array
// instead if you wanted.
List<String> ret = new ArrayList<String>((text.length() + size - 1) / size);
for (int start = 0; start < text.length(); start += size) {
ret.add(text.substring(start, Math.min(text.length(), start + size)));
}
return ret;
}
Note: this assumes a 1:1 mapping of UTF-16 code unit (char, effectively) with "character". That assumption breaks down for characters outside the Basic Multilingual Plane, such as emoji, and (depending on how you want to count things) combining characters.
I don't think it's really worth using a regex for this.
EDIT: My reasoning for not using a regex:
This doesn't use any of the real pattern matching of regexes. It's just counting.
I suspect the above will be more efficient, although in most cases it won't matter
If you need to use variable sizes in different places, you've either got repetition or a helper function to build the regex itself based on a parameter - ick.
The regex provided in another answer firstly didn't compile (invalid escaping), and then didn't work. My code worked first time. That's more a testament to the usability of regexes vs plain code, IMO.
This is very easy with Google Guava:
for(final String token :
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
Output:
Theq
uick
brow
nfox
jump
s
Or if you need the result as an array, you can use this code:
String[] tokens =
Iterables.toArray(
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps"),
String.class
);
Reference:
Splitter.fixedLength()
Splitter.split()
Iterables.toArray()
Note: Splitter construction is shown inline above, but since Splitters are immutable and reusable, it's a good practice to store them in constants:
private static final Splitter FOUR_LETTERS = Splitter.fixedLength(4);
// more code
for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
If you're using Google's guava general-purpose libraries (and quite honestly, any new Java project probably should be), this is insanely trivial with the Splitter class:
for (String substring : Splitter.fixedLength(4).split(inputString)) {
doSomethingWith(substring);
}
and that's it. Easy as!
public static String[] split(String src, int len) {
String[] result = new String[(int)Math.ceil((double)src.length()/(double)len)];
for (int i=0; i<result.length; i++)
result[i] = src.substring(i*len, Math.min(src.length(), (i+1)*len));
return result;
}
public String[] splitInParts(String s, int partLength)
{
int len = s.length();
// Number of parts
int nparts = (len + partLength - 1) / partLength;
String parts[] = new String[nparts];
// Break into parts
int offset= 0;
int i = 0;
while (i < nparts)
{
parts[i] = s.substring(offset, Math.min(offset + partLength, len));
offset += partLength;
i++;
}
return parts;
}
Here's a one-liner version which uses Java 8 IntStream to determine the indexes of the slice beginnings:
String x = "Thequickbrownfoxjumps";
String[] result = IntStream
.iterate(0, i -> i + 4)
.limit((int) Math.ceil(x.length() / 4.0))
.mapToObj(i ->
x.substring(i, Math.min(i + 4, x.length())
)
.toArray(String[]::new);
I'd rather this simple solution:
String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
System.out.println(content.substring(0, 4));
content = content.substring(4);
}
System.out.println(content);
A StringBuilder version:
public static List<String> getChunks(String s, int chunkSize)
{
List<String> chunks = new ArrayList<>();
StringBuilder sb = new StringBuilder(s);
while(!(sb.length() ==0))
{
chunks.add(sb.substring(0, chunkSize));
sb.delete(0, chunkSize);
}
return chunks;
}
i use the following java 8 solution:
public static List<String> splitString(final String string, final int chunkSize) {
final int numberOfChunks = (string.length() + chunkSize - 1) / chunkSize;
return IntStream.range(0, numberOfChunks)
.mapToObj(index -> string.substring(index * chunkSize, Math.min((index + 1) * chunkSize, string.length())))
.collect(toList());
}
You can use substring from String.class (handling exceptions) or from Apache lang commons (it handles exceptions for you)
static String substring(String str, int start, int end)
Put it inside a loop and you are good to go.
In case you want to split the string equally backwards, i.e. from right to left, for example, to split 1010001111 to [10, 1000, 1111], here's the code:
/**
* #param s the string to be split
* #param subLen length of the equal-length substrings.
* #param backwards true if the splitting is from right to left, false otherwise
* #return an array of equal-length substrings
* #throws ArithmeticException: / by zero when subLen == 0
*/
public static String[] split(String s, int subLen, boolean backwards) {
assert s != null;
int groups = s.length() % subLen == 0 ? s.length() / subLen : s.length() / subLen + 1;
String[] strs = new String[groups];
if (backwards) {
for (int i = 0; i < groups; i++) {
int beginIndex = s.length() - subLen * (i + 1);
int endIndex = beginIndex + subLen;
if (beginIndex < 0)
beginIndex = 0;
strs[groups - i - 1] = s.substring(beginIndex, endIndex);
}
} else {
for (int i = 0; i < groups; i++) {
int beginIndex = subLen * i;
int endIndex = beginIndex + subLen;
if (endIndex > s.length())
endIndex = s.length();
strs[i] = s.substring(beginIndex, endIndex);
}
}
return strs;
}
Here is a one liner implementation using Java8 streams:
String input = "Thequickbrownfoxjumps";
final AtomicInteger atomicInteger = new AtomicInteger(0);
Collection<String> result = input.chars()
.mapToObj(c -> String.valueOf((char)c) )
.collect(Collectors.groupingBy(c -> atomicInteger.getAndIncrement() / 4
,Collectors.joining()))
.values();
It gives the following output:
[Theq, uick, brow, nfox, jump, s]
Java 8 solution (like this but a bit simpler):
public static List<String> partition(String string, int partSize) {
List<String> parts = IntStream.range(0, string.length() / partSize)
.mapToObj(i -> string.substring(i * partSize, (i + 1) * partSize))
.collect(toList());
if ((string.length() % partSize) != 0)
parts.add(string.substring(string.length() / partSize * partSize));
return parts;
}
Use code points to handle all characters
Here is a solution:
Works with all 143,859 Unicode characters
Allows you to examine or manipulate each resulting string, if you have further logic to process.
To work with all Unicode characters, avoid the obsolete char type. And avoid char-based utilities. Instead, use code point integer numbers.
Call String#codePoints to get an IntStream object, a stream of int values. In the code below, we collect those int values into an array. Then we loop the array, for each integer we append the character assigned to that number to our StringBuilder object. Every nth character, we add a string to our master list, and empty the StringBuilder.
String input = "Thequickbrownfoxjumps";
int chunkSize = 4 ;
int[] codePoints = input.codePoints().toArray(); // `String#codePoints` returns an `IntStream`. Collect the elements of that stream into an array.
int initialCapacity = ( ( codePoints.length / chunkSize ) + 1 );
List < String > strings = new ArrayList <>( initialCapacity );
StringBuilder sb = new StringBuilder();
for ( int i = 0 ; i < codePoints.length ; i++ )
{
sb.appendCodePoint( codePoints[ i ] );
if ( 0 == ( ( i + 1 ) % chunkSize ) ) // Every nth code point.
{
strings.add( sb.toString() ); // Remember this iteration's value.
sb.setLength( 0 ); // Clear the contents of the `StringBuilder` object.
}
}
if ( sb.length() > 0 ) // If partial string leftover, save it too. Or not… just delete this `if` block.
{
strings.add( sb.toString() ); // Remember last iteration's value.
}
System.out.println( "strings = " + strings );
strings = [Theq, uick, brow, nfox, jump, s]
This works with non-Latin characters. Here we replace q with FACE WITH MEDICAL MASK.
String text = "The😷uickbrownfoxjumps"
strings = [The😷, uick, brow, nfox, jump, s]
Here is my version based on RegEx and Java 8 streams. It's worth to mention that Matcher.results() method is available since Java 9.
Test included.
public static List<String> splitString(String input, int splitSize) {
Matcher matcher = Pattern.compile("(?:(.{" + splitSize + "}))+?").matcher(input);
return matcher.results().map(MatchResult::group).collect(Collectors.toList());
}
#Test
public void shouldSplitStringToEqualLengthParts() {
String anyValidString = "Split me equally!";
String[] expectedTokens2 = {"Sp", "li", "t ", "me", " e", "qu", "al", "ly"};
String[] expectedTokens3 = {"Spl", "it ", "me ", "equ", "all"};
Assert.assertArrayEquals(expectedTokens2, splitString(anyValidString, 2).toArray());
Assert.assertArrayEquals(expectedTokens3, splitString(anyValidString, 3).toArray());
}
The simplest solution is:
/**
* Slices string by passed - in slice length.
* If passed - in string is null or slice length less then 0 throws IllegalArgumentException.
* #param toSlice string to slice
* #param sliceLength slice length
* #return List of slices
*/
public static List<String> stringSlicer(String toSlice, int sliceLength) {
if (toSlice == null) {
throw new IllegalArgumentException("Passed - in string is null");
}
if (sliceLength < 0) {
throw new IllegalArgumentException("Slice length can not be less then 0");
}
if (toSlice.isEmpty() || toSlice.length() <= sliceLength) {
return List.of(toSlice);
}
return Arrays.stream(toSlice.split(String.format("(?s)(?<=\\G.{%d})", sliceLength))).collect(Collectors.toList());
}
I asked #Alan Moore in a comment to the accepted solution how strings with newlines could be handled. He suggested using DOTALL.
Using his suggestion I created a small sample of how that works:
public void regexDotAllExample() throws UnsupportedEncodingException {
final String input = "The\nquick\nbrown\r\nfox\rjumps";
final String regex = "(?<=\\G.{4})";
Pattern splitByLengthPattern;
String[] split;
splitByLengthPattern = Pattern.compile(regex);
split = splitByLengthPattern.split(input);
System.out.println("---- Without DOTALL ----");
for (int i = 0; i < split.length; i++) {
byte[] s = split[i].getBytes("utf-8");
System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s);
}
/* Output is a single entry longer than the desired split size:
---- Without DOTALL ----
[Idx: 0, length: 26] - [B#17cdc4a5
*/
//DOTALL suggested in Alan Moores comment on SO: https://stackoverflow.com/a/3761521/1237974
splitByLengthPattern = Pattern.compile(regex, Pattern.DOTALL);
split = splitByLengthPattern.split(input);
System.out.println("---- With DOTALL ----");
for (int i = 0; i < split.length; i++) {
byte[] s = split[i].getBytes("utf-8");
System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s);
}
/* Output is as desired 7 entries with each entry having a max length of 4:
---- With DOTALL ----
[Idx: 0, length: 4] - [B#77b22abc
[Idx: 1, length: 4] - [B#5213da08
[Idx: 2, length: 4] - [B#154f6d51
[Idx: 3, length: 4] - [B#1191ebc5
[Idx: 4, length: 4] - [B#30ddb86
[Idx: 5, length: 4] - [B#2c73bfb
[Idx: 6, length: 2] - [B#6632dd29
*/
}
But I like #Jon Skeets solution in https://stackoverflow.com/a/3760193/1237974 also. For maintainability in larger projects where not everyone are equally experienced in Regular expressions I would probably use Jons solution.
Another brute force solution could be,
String input = "thequickbrownfoxjumps";
int n = input.length()/4;
String[] num = new String[n];
for(int i = 0, x=0, y=4; i<n; i++){
num[i] = input.substring(x,y);
x += 4;
y += 4;
System.out.println(num[i]);
}
Where the code just steps through the string with substrings
import static java.lang.System.exit;
import java.util.Scanner;
import Java.util.Arrays.*;
public class string123 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("Enter String");
String r=sc.nextLine();
String[] s=new String[10];
int len=r.length();
System.out.println("Enter length Of Sub-string");
int l=sc.nextInt();
int last;
int f=0;
for(int i=0;;i++){
last=(f+l);
if((last)>=len) last=len;
s[i]=r.substring(f,last);
// System.out.println(s[i]);
if (last==len)break;
f=(f+l);
}
System.out.print(Arrays.tostring(s));
}}
Result
Enter String
Thequickbrownfoxjumps
Enter length Of Sub-string
4
["Theq","uick","brow","nfox","jump","s"]
#Test
public void regexSplit() {
String source = "Thequickbrownfoxjumps";
// define matcher, any char, min length 1, max length 4
Matcher matcher = Pattern.compile(".{1,4}").matcher(source);
List<String> result = new ArrayList<>();
while (matcher.find()) {
result.add(source.substring(matcher.start(), matcher.end()));
}
String[] expected = {"Theq", "uick", "brow", "nfox", "jump", "s"};
assertArrayEquals(result.toArray(), expected);
}
public static String[] split(String input, int length) throws IllegalArgumentException {
if(length == 0 || input == null)
return new String[0];
int lengthD = length * 2;
int size = input.length();
if(size == 0)
return new String[0];
int rep = (int) Math.ceil(size * 1d / length);
ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_16LE));
String[] out = new String[rep];
byte[] buf = new byte[lengthD];
int d = 0;
for (int i = 0; i < rep; i++) {
try {
d = stream.read(buf);
} catch (IOException e) {
e.printStackTrace();
}
if(d != lengthD)
{
out[i] = new String(buf,0,d, StandardCharsets.UTF_16LE);
continue;
}
out[i] = new String(buf, StandardCharsets.UTF_16LE);
}
return out;
}
public static List<String> getSplittedString(String stringtoSplit,
int length) {
List<String> returnStringList = new ArrayList<String>(
(stringtoSplit.length() + length - 1) / length);
for (int start = 0; start < stringtoSplit.length(); start += length) {
returnStringList.add(stringtoSplit.substring(start,
Math.min(stringtoSplit.length(), start + length)));
}
return returnStringList;
}

Categories

Resources