String concatenation in solidity? - string

How do I concatenate strings in solidity?
var str = 'asdf'
var b = str + 'sdf'
seems not to work.
I looked up the documentation and there is not much mentioned about string concatenation.
But it is stated that it works with the dot ('.')?
"[...] a mapping key k is located at sha3(k . p) where . is concatenation."
Didn't work out for me too. :/

An answer from the Ethereum Stack Exchange:
A library can be used, for example:
import "github.com/Arachnid/solidity-stringutils/strings.sol";
contract C {
using strings for *;
string public s;
function foo(string s1, string s2) {
s = s1.toSlice().concat(s2.toSlice());
}
}
Use the above for a quick test that you can modify for your needs.
Since concatenating strings needs to be done manually for now, and doing so in a contract may consume unnecessary gas (new string has to be allocated and then each character written), it is worth considering what's the use case that needs string concatenation?
If the DApp can be written in a way so that the frontend concatenates the strings, and then passes it to the contract for processing, this could be a better design.
Or, if a contract wants to hash a single long string, note that all the built-in hashing functions in Solidity (sha256, ripemd160, sha3) take a variable number of arguments and will perform the concatenation before computing the hash.

You can't concatenate strings. You also can not check equals (str0 == str1) yet. The string type was just recently added back to the language so it will probably take a while until all of this works. What you can do (which they recently added) is to use strings as keys for mappings.
The concatenation you're pointing to is how storage addresses are computed based on field types and such, but that's handled by the compiler.

Here is another way to concat strings in Solidity. It is also shown in this tutorial:
pragma solidity ^0.4.19;
library Strings {
function concat(string _base, string _value) internal returns (string) {
bytes memory _baseBytes = bytes(_base);
bytes memory _valueBytes = bytes(_value);
string memory _tmpValue = new string(_baseBytes.length + _valueBytes.length);
bytes memory _newValue = bytes(_tmpValue);
uint i;
uint j;
for(i=0; i<_baseBytes.length; i++) {
_newValue[j++] = _baseBytes[i];
}
for(i=0; i<_valueBytes.length; i++) {
_newValue[j++] = _valueBytes[i];
}
return string(_newValue);
}
}
contract TestString {
using Strings for string;
function testConcat(string _base) returns (string) {
return _base.concat("_Peter");
}
}

You have to do it manually for now
Solidity doesn't provide built-in string concatenation and string comparison.
However, you can find libraries and contracts that implement string concatenation and comparison.
StringUtils.sol library implements string comparison.
Oraclize contract srtConcat function implements string concatenation.
If you need concatenation to get a hash of a result string, note that there are built-in hashing functions in Solidity: sha256, ripemd160, sha3. They take a variable number of arguments and perform the concatenation before computing the hash.

You could leverage abi.encodePacked:
bytes memory b;
b = abi.encodePacked("hello");
b = abi.encodePacked(b, " world");
string memory s = string(b);
// s == "hello world"

I used this method to concat strings. Hope this is helpful
function cancat(string memory a, string memory b) public view returns(string memory){
return(string(abi.encodePacked(a,"/",b)));
}

you can do it very easily with the low-level function of solidity with
abi.encodePacked(str,b)
one important thing to remember is , first typecast it to string ie:
string(abi.encodePacked(str, b))
your function will return
return string(abi.encodePacked(str, b));
its easy and gas saving too :)

Solidity does not offer a native way to concatenate strings so we can use abi.encodePacked(). Please refer Doc Link for more information
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract AX{
string public s1 = "aaa";
string public s2 = "bbb";
string public new_str;
function concatenate() public {
new_str = string(abi.encodePacked(s1, s2));
}
}

In solidity, working with a string is a headache. If you want to perform string action, you have to consider converting string to byte and then convert back to string again. this demo contract will concatenate strings
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract String{
function concatenate(string memory firstName,string memory lastName) public pure returns (string memory fullName) {
bytes memory full=string.concat(bytes(firstName),bytes(lastName));
return string(full);
}
}

Examples above do not work perfect.
For example, try concat these values
["10","11","12","13","133"] and you will get ["1","1","1","1","13"]
There is some bug.
And you also do not need use Library for it. Because library is very huge for it.
Use this method:
function concat(string _a, string _b) constant returns (string){
bytes memory bytes_a = bytes(_a);
bytes memory bytes_b = bytes(_b);
string memory length_ab = new string(bytes_a.length + bytes_b.length);
bytes memory bytes_c = bytes(length_ab);
uint k = 0;
for (uint i = 0; i < bytes_a.length; i++) bytes_c[k++] = bytes_a[i];
for (i = 0; i < bytes_b.length; i++) bytes_c[k++] = bytes_b[i];
return string(bytes_c);
}

You can do this with the ABI encoder. Solidity can not concatenate strings natiely because they are dynamically sized. You have to hash them to 32bytes.
pragma solidity 0.5.0;
pragma experimental ABIEncoderV2;
contract StringUtils {
function conc( string memory tex) public payable returns(string
memory result){
string memory _result = string(abi.encodePacked('-->', ": ", tex));
return _result;
}
}

Compared to languages such as Python and JavaScript, there is no direct way of doing this in Solidity. I would do something like the below to concatenate two strings:
//SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 < 0.9.0;
contract test {
function appendStrings(string memory string1, string memory string2) public pure returns(string memory) {
return string(abi.encodePacked(string1, string2));
}
}
Please see the screenshot below for the result of concatenating two strings ('asdf' and 'sdf') in Remix Ethereum IDE.

You can use this approach to concat and check equal string.
// concat strgin
string memory result = string(abi. encodePacked("Hello", "World"));
// check qual
if (keccak256(abi.encodePacked("banana")) == keccak256(abi.encodePacked("banana"))) {
// your logic here
}

After 0.8.4 version of Solidity, you can now concat bytes without using encodePacked()
See the issue: here
//SPDX-License-Identifier: GPT-3
pragma solidity >=0.8.4;
library Strings {
function concat(string memory a, string memory b) internal pure returns (string memory) {
return string(bytes.concat(bytes(a),bytes(b)));
}
}
Usage:
contract Implementation {
using Strings for string;
string a = "first";
string b = "second";
string public c;
constructor() {
c = a.concat(b); // "firstsecond"
}
}

Related

How to collect a string to a stack of characters in Java 8? [duplicate]

I would like to convert the string containing abc to a list of characters and a hashset of characters. How can I do that in Java ?
List<Character> charList = new ArrayList<Character>("abc".toCharArray());
In Java8 you can use streams I suppose.
List of Character objects:
List<Character> chars = str.chars()
.mapToObj(e->(char)e).collect(Collectors.toList());
And set could be obtained in a similar way:
Set<Character> charsSet = str.chars()
.mapToObj(e->(char)e).collect(Collectors.toSet());
You will have to either use a loop, or create a collection wrapper like Arrays.asList which works on primitive char arrays (or directly on strings).
List<Character> list = new ArrayList<Character>();
Set<Character> unique = new HashSet<Character>();
for(char c : "abc".toCharArray()) {
list.add(c);
unique.add(c);
}
Here is an Arrays.asList like wrapper for strings:
public List<Character> asList(final String string) {
return new AbstractList<Character>() {
public int size() { return string.length(); }
public Character get(int index) { return string.charAt(index); }
};
}
This one is an immutable list, though. If you want a mutable list, use this with a char[]:
public List<Character> asList(final char[] string) {
return new AbstractList<Character>() {
public int size() { return string.length; }
public Character get(int index) { return string[index]; }
public Character set(int index, Character newVal) {
char old = string[index];
string[index] = newVal;
return old;
}
};
}
Analogous to this you can implement this for the other primitive types.
Note that using this normally is not recommended, since for every access you
would do a boxing and unboxing operation.
The Guava library contains similar List wrapper methods for several primitive array classes, like Chars.asList, and a wrapper for String in Lists.charactersOf(String).
The lack of a good way to convert between a primitive array and a collection of its corresponding wrapper type is solved by some third party libraries. Guava, a very common one, has a convenience method to do the conversion:
List<Character> characterList = Chars.asList("abc".toCharArray());
Set<Character> characterSet = new HashSet<Character>(characterList);
Use a Java 8 Stream.
myString.chars().mapToObj(i -> (char) i).collect(Collectors.toList());
Breakdown:
myString
.chars() // Convert to an IntStream
.mapToObj(i -> (char) i) // Convert int to char, which gets boxed to Character
.collect(Collectors.toList()); // Collect in a List<Character>
(I have absolutely no idea why String#chars() returns an IntStream.)
The most straightforward way is to use a for loop to add elements to a new List:
String abc = "abc";
List<Character> charList = new ArrayList<Character>();
for (char c : abc.toCharArray()) {
charList.add(c);
}
Similarly, for a Set:
String abc = "abc";
Set<Character> charSet = new HashSet<Character>();
for (char c : abc.toCharArray()) {
charSet.add(c);
}
List<String> result = Arrays.asList("abc".split(""));
Create an empty list of Character and then make a loop to get every character from the array and put them in the list one by one.
List<Character> characterList = new ArrayList<Character>();
char arrayChar[] = abc.toCharArray();
for (char aChar : arrayChar)
{
characterList.add(aChar); // autoboxing
}
You can do this without boxing if you use Eclipse Collections:
CharAdapter abc = Strings.asChars("abc");
CharList list = abc.toList();
CharSet set = abc.toSet();
CharBag bag = abc.toBag();
Because CharAdapter is an ImmutableCharList, calling collect on it will return an ImmutableList.
ImmutableList<Character> immutableList = abc.collect(Character::valueOf);
If you want to return a boxed List, Set or Bag of Character, the following will work:
LazyIterable<Character> lazyIterable = abc.asLazy().collect(Character::valueOf);
List<Character> list = lazyIterable.toList();
Set<Character> set = lazyIterable.toSet();
Bag<Character> set = lazyIterable.toBag();
Note: I am a committer for Eclipse Collections.
IntStream can be used to access each character and add them to the list.
String str = "abc";
List<Character> charList = new ArrayList<>();
IntStream.range(0,str.length()).forEach(i -> charList.add(str.charAt(i)));
Using Java 8 - Stream Funtion:
Converting A String into Character List:
ArrayList<Character> characterList = givenStringVariable
.chars()
.mapToObj(c-> (char)c)
.collect(collectors.toList());
Converting A Character List into String:
String givenStringVariable = characterList
.stream()
.map(String::valueOf)
.collect(Collectors.joining())
To get a list of Characters / Strings -
List<String> stringsOfCharacters = string.chars().
mapToObj(i -> (char)i).
map(c -> c.toString()).
collect(Collectors.toList());

Why String s1==s2 return false if I add +"" and return True If I used s1==s2

public class MainDemo
{
public void comp()
{
String s1 = "abc";
String s2 = "abc";
System.out.print(""+s1==s2); // Why return false??? Plz clear my doubt?
System.out.println(s1==s2);//And why true for this
}
/**
* #param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
MainDemo obj=new MainDemo();
obj.comp();
}
}
#####################################################
Why this return false ??
System.out.print(""+s1==s2); // Why return false???
Please clear my doubt?
Edited
Can someone Tell me how do I check the instance Value
EDITED 2
System.out.println(s1.hashCode()); // BOTH ARE SAME
System.out.println(s2.hashCode());// BOTH ARE SAME
Then What happened to this?????
Comparing String like this is not a good idea, use a1.equals(a2); Well back to answer of your question.
String a1="abc";
String a2="abc";
System.out.println(a1==a2); // true
System.out.println(""+a1==a2); // false
System.out.println(""+(a1==a2)); // true
Look at this ""+a1. If you try ""+a1==a1 it return false, confused? don't be because ""+a1 is just a new String object on heap that points to "abc" in the string pool. while ""+(a1==a2) compares first and than append like this :""+(true)
As I suggested use a1.equals(a2); instead of == with strings
official: here
equals(Object anObject) Compares this string to the specified object.
""+s1 is a new String and so not the same Object as s2. You should you equals to compare values of Strings in Java. For more information and examples have a look at: How do I compare strings in Java?
If I closed the s1==s2 in bracket like this (s1==s2) Its return true.....Confuseed
Well, these parentheses are used to specify operator precendence. Same as in mathematics.
System.out.println("" + (s1 == s2));
That will just do
System.out.println("" + true);
What you had before was equivalent to
System.out.println( ( "" + s1) == s2);
The == operator checks whether the references to the String objects are equal.
And in String.equals(""); checks contains of both Strings.
Please Find my comments in your code.. Also read unicode etc from Core Java by Cay Horstman
public class MainDemo {
public void comp() {
String s1 = "abc";//String s1 "abc"
String s2 = "abc";//String s2 "abc"
System.out.print(""+s1==s2); // Why return false??? Plz clear my doubt? // its "null+abc"=="abc" // mind the null in first "abc" and tell they equal???
System.out.println(s1==s2);//And why true for this // because here its "abc"=="abc" no null added to the string
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MainDemo obj=new MainDemo();
obj.comp();
}
}
String s1 = "abc";
String s2 = "abc";
System.out.print(""+s1==s2); // comparing a reference to object on heap with the reference to interned string in string pool
System.out.println(s1==s2); // comparing references to same interned string in the string pool
String s1 and String s2 are being assigned string literals i-e there value is known at compile time. JVM would intern them in the string pool and both s1 and s2 would actually be pointing to same string in the string pool.
when you do (s1==s2); s1 and s2 both reference to the same string in the string pool so they return true.
but doing (""+s1==s2); returns false because ""+s1 would be evaluated on runtime. JVM would make a string object on the heap that in turn would point to "abc" in the string pool.
enforce string interning using
System.out.println((""+s1).intern() == s2); // true because of explicit interning
Generally, its better to use .equals() to compare strings. If you want to directly compare the strings you must know how JVM is handling strings behind the scenes.
read What is Java String interning? for further clarification.
Because String s1's length got changed now. Check length of those strings using string length function and see what it returns.

Just Difference in C#

What is the differ between string.Join & string.Concat
similarly what is the diff between string.Equals & string.Compare
Show me with some example for each. I already searched but didn't understand.
Thanks in Advance.
Join combines several strings with a separator in between; this is most often used if you have a list and want to format it in a way that there is a separator (e.g. a comma) between each element. Concat just appends them all after another. In a way, Join with an empty separator is equivalent to Concat.
Equals determines whether two strings are considered equal, Compare is for determining a sort order between two strings.
Honestly, though, this is all explained very well in the documentation.
With .NET 4.0, String.Join() uses StringBuilder class internally so it is more efficient.
Whereas String.Concat() uses basic concatenation of String using "+" which is of course not an efficient approach as String is immutable.
I compared String.Join() in .NET 2.0 framework where its implementation was different(it wasn't using StringBuilder in .NET 2.0). But with .NET 4.0, String.Join() is using StringBuilder() internally so its like easy wrapper on top of StringBuilder() for string concatenation.
Microsoft even recommends using StringBuilder class for any string concatenation.
Program that joins strings [C#]
using System;
class Program
{
static void Main()
{
string[] arr = { "one", "two", "three" };
// "string" can be lowercase, or...
Console.WriteLine(string.Join(",", arr));
// ... "String" can be uppercase:
Console.WriteLine(String.Join(",", arr));
}
}
Output -
one,two,three
one,two,three
Concat:
using System;
class Program
{
static void Main()
{
// 1.
// New string called s1.
string s1 = "string2";
// 2.
// Add another string to the start.
string s2 = "string1" + s1;
// 3.
// Write to console.
Console.WriteLine(s2);
}
}
Output -
string1string2
these two methods are quite related. Although it hasn't been done, equals could have been implemented using compareTo:
public boolean equals(Object o)
{
if (this == anObject)
{
return true;
}
if (o instanceof String)
{
String s = (String)o;
return compareTo(s) == 0;
}
return false;
}
Also, s1.equals(s2) == true implies s1.compareTo(s2) == 0 (and vice versa), and s1.equals(s2) == false implies s1.compareTo(s2) != 0 (and vice versa).
However, and this is important, this does not have to be the case for all classes. It is for String, but no rule prohibits different natural orders for other classes.

Sorting a string using another sorting order string [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I saw this in an interview question ,
Given a sorting order string, you are asked to sort the input string based on the given sorting order string.
for example if the sorting order string is dfbcae
and the Input string is abcdeeabc
the output should be dbbccaaee.
any ideas on how to do this , in an efficient way ?
The Counting Sort option is pretty cool, and fast when the string to be sorted is long compared to the sort order string.
create an array where each index corresponds to a letter in the alphabet, this is the count array
for each letter in the sort target, increment the index in the count array which corresponds to that letter
for each letter in the sort order string
add that letter to the end of the output string a number of times equal to it's count in the count array
Algorithmic complexity is O(n) where n is the length of the string to be sorted. As the Wikipedia article explains we're able to beat the lower bound on standard comparison based sorting because this isn't a comparison based sort.
Here's some pseudocode.
char[26] countArray;
foreach(char c in sortTarget)
{
countArray[c - 'a']++;
}
int head = 0;
foreach(char c in sortOrder)
{
while(countArray[c - 'a'] > 0)
{
sortTarget[head] = c;
head++;
countArray[c - 'a']--;
}
}
Note: this implementation requires that both strings contain only lowercase characters.
Here's a nice easy to understand algorithm that has decent algorithmic complexity.
For each character in the sort order string
scan string to be sorted, starting at first non-ordered character (you can keep track of this character with an index or pointer)
when you find an occurrence of the specified character, swap it with the first non-ordered character
increment the index for the first non-ordered character
This is O(n*m), where n is the length of the string to be sorted and m is the length of the sort order string. We're able to beat the lower bound on comparison based sorting because this algorithm doesn't really use comparisons. Like Counting Sort it relies on the fact that you have a predefined finite external ordering set.
Here's some psuedocode:
int head = 0;
foreach(char c in sortOrder)
{
for(int i = head; i < sortTarget.length; i++)
{
if(sortTarget[i] == c)
{
// swap i with head
char temp = sortTarget[head];
sortTarget[head] = sortTarget[i];
sortTarget[i] = temp;
head++;
}
}
}
In Python, you can just create an index and use that in a comparison expression:
order = 'dfbcae'
input = 'abcdeeabc'
index = dict([ (y,x) for (x,y) in enumerate(order) ])
output = sorted(input, cmp=lambda x,y: index[x] - index[y])
print 'input=',''.join(input)
print 'output=',''.join(output)
gives this output:
input= abcdeeabc
output= dbbccaaee
Use binary search to find all the "split points" between different letters, then use the length of each segment directly. This will be asymptotically faster then naive counting sort, but will be harder to implement:
Use an array of size 26*2 to store the begin and end of each letter;
Inspect the middle element, see if it is different from the element left to it. If so, then this is the begin for the middle element and end for the element before it;
Throw away the segment with identical begin and end (if there are any), recursively apply this algorithm.
Since there are at most 25 "split"s, you won't have to do the search for more than 25 segemnts, and for each segment it is O(logn). Since this is constant * O(logn), the algorithm is O(nlogn).
And of course, just use counting sort will be easier to implement:
Use an array of size 26 to record the number of different letters;
Scan the input string;
Output the string in the given sorting order.
This is O(n), n being the length of the string.
Interview questions are generally about thought process and don't usually care too much about language features, but I couldn't resist posting a VB.Net 4.0 version anyway.
"Efficient" can mean two different things. The first is "what's the fastest way to make a computer execute a task" and the second is "what's the fastest that we can get a task done". They might sound the same but the first can mean micro-optimizations like int vs short, running timers to compare execution times and spending a week tweaking every millisecond out of an algorithm. The second definition is about how much human time would it take to create the code that does the task (hopefully in a reasonable amount of time). If code A runs 20 times faster than code B but code B took 1/20th of the time to write, depending on the granularity of the timer (1ms vs 20ms, 1 week vs 20 weeks), each version could be considered "efficient".
Dim input = "abcdeeabc"
Dim sort = "dfbcae"
Dim SortChars = sort.ToList()
Dim output = New String((From c In input.ToList() Select c Order By SortChars.IndexOf(c)).ToArray())
Trace.WriteLine(output)
Here is my solution to the question
import java.util.*;
import java.io.*;
class SortString
{
public static void main(String arg[])throws IOException
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
// System.out.println("Enter 1st String :");
// System.out.println("Enter 1st String :");
// String s1=br.readLine();
// System.out.println("Enter 2nd String :");
// String s2=br.readLine();
String s1="tracctor";
String s2="car";
String com="";
String uncom="";
for(int i=0;i<s2.length();i++)
{
if(s1.contains(""+s2.charAt(i)))
{
com=com+s2.charAt(i);
}
}
System.out.println("Com :"+com);
for(int i=0;i<s1.length();i++)
if(!com.contains(""+s1.charAt(i)))
uncom=uncom+s1.charAt(i);
System.out.println("Uncom "+uncom);
System.out.println("Combined "+(com+uncom));
HashMap<String,Integer> h1=new HashMap<String,Integer>();
for(int i=0;i<s1.length();i++)
{
String m=""+s1.charAt(i);
if(h1.containsKey(m))
{
int val=(int)h1.get(m);
val=val+1;
h1.put(m,val);
}
else
{
h1.put(m,new Integer(1));
}
}
StringBuilder x=new StringBuilder();
for(int i=0;i<com.length();i++)
{
if(h1.containsKey(""+com.charAt(i)))
{
int count=(int)h1.get(""+com.charAt(i));
while(count!=0)
{x.append(""+com.charAt(i));count--;}
}
}
x.append(uncom);
System.out.println("Sort "+x);
}
}
Here is my version which is O(n) in time. Instead of unordered_map, I could have just used a char array of constant size. i.,e. char char_count[256] (and done ++char_count[ch - 'a'] ) assuming the input strings has all ASCII small characters.
string SortOrder(const string& input, const string& sort_order) {
unordered_map<char, int> char_count;
for (auto ch : input) {
++char_count[ch];
}
string res = "";
for (auto ch : sort_order) {
unordered_map<char, int>::iterator it = char_count.find(ch);
if (it != char_count.end()) {
string s(it->second, it->first);
res += s;
}
}
return res;
}
private static String sort(String target, String reference) {
final Map<Character, Integer> referencesMap = new HashMap<Character, Integer>();
for (int i = 0; i < reference.length(); i++) {
char key = reference.charAt(i);
if (!referencesMap.containsKey(key)) {
referencesMap.put(key, i);
}
}
List<Character> chars = new ArrayList<Character>(target.length());
for (int i = 0; i < target.length(); i++) {
chars.add(target.charAt(i));
}
Collections.sort(chars, new Comparator<Character>() {
#Override
public int compare(Character o1, Character o2) {
return referencesMap.get(o1).compareTo(referencesMap.get(o2));
}
});
StringBuilder sb = new StringBuilder();
for (Character c : chars) {
sb.append(c);
}
return sb.toString();
}
In C# I would just use the IComparer Interface and leave it to Array.Sort
void Main()
{
// we defin the IComparer class to define Sort Order
var sortOrder = new SortOrder("dfbcae");
var testOrder = "abcdeeabc".ToCharArray();
// sort the array using Array.Sort
Array.Sort(testOrder, sortOrder);
Console.WriteLine(testOrder.ToString());
}
public class SortOrder : IComparer
{
string sortOrder;
public SortOrder(string sortOrder)
{
this.sortOrder = sortOrder;
}
public int Compare(object obj1, object obj2)
{
var obj1Index = sortOrder.IndexOf((char)obj1);
var obj2Index = sortOrder.IndexOf((char)obj2);
if(obj1Index == -1 || obj2Index == -1)
{
throw new Exception("character not found");
}
if(obj1Index > obj2Index)
{
return 1;
}
else if (obj1Index == obj2Index)
{
return 0;
}
else
{
return -1;
}
}
}

How to truncate a string in groovy?

How to truncate string in groovy?
I used:
def c = truncate("abscd adfa dasfds ghisgirs fsdfgf", 10)
but getting error.
The Groovy community has added a take() method which can be used for easy and safe string truncation.
Examples:
"abscd adfa dasfds ghisgirs fsdfgf".take(10) //"abscd adfa"
"It's groovy, man".take(4) //"It's"
"It's groovy, man".take(10000) //"It's groovy, man" (no exception thrown)
There's also a corresponding drop() method:
"It's groovy, man".drop(15) //"n"
"It's groovy, man".drop(5).take(6) //"groovy"
Both take() and drop() are relative to the start of the string, as in "take from the front" and "drop from the front".
Online Groovy console to run the examples:
https://ideone.com/zQD9Om — (note: the UI is really bad)
For additional information, see "Add a take method to Collections, Iterators, Arrays":
https://issues.apache.org/jira/browse/GROOVY-4865
In Groovy, strings can be considered as ranges of characters. As a consequence, you can simply use range indexing features of Groovy and do myString[startIndex..endIndex].
As an example,
"012345678901234567890123456789"[0..10]
outputs
"0123456789"
we can simply use range indexing features of Groovy and do someString[startIndex..endIndex].
For example:
def str = "abcdefgh"
def outputTrunc = str[2..5]
print outputTrunc
Console:
"cde"
To avoid word break you can make use of the java.text.BreakIterator. This will truncate a string to the closest word boundary after a number of characters.
Example
package com.example
import java.text.BreakIterator
class exampleClass {
private truncate( String content, int contentLength ) {
def result
//Is content > than the contentLength?
if(content.size() > contentLength) {
BreakIterator bi = BreakIterator.getWordInstance()
bi.setText(content);
def first_after = bi.following(contentLength)
//Truncate
result = content.substring(0, first_after) + "..."
} else {
result = content
}
return result
}
}
Here's my helper functions to to solve this kinda problem. In many cases you'll probably want to truncate by-word rather than by-characters so I pasted the function for that as well.
public static String truncate(String self, int limit) {
if (limit >= self.length())
return self;
return self.substring(0, limit);
}
public static String truncate(String self, int hardLimit, String nonWordPattern) {
if (hardLimit >= self.length())
return self;
int softLimit = 0;
Matcher matcher = compile(nonWordPattern, CASE_INSENSITIVE | UNICODE_CHARACTER_CLASS).matcher(self);
while (matcher.find()) {
if (matcher.start() > hardLimit)
break;
softLimit = matcher.start();
}
return truncate(self, softLimit);
}

Resources