How to truncate a string in groovy? - 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);
}

Related

I need to create a function in Groovy that has a single integer as a parameter and returns the number of significant figures it contains

Long story short, I'm working in a system that only works with groovy in its expression editor, and I need to create a function that returns the number of significant figures an integer has. I've found the following function in stack overflow for Java, however it doesnt seem like groovy (or the system itself) likes the regex:
String myfloat = "0.0120";
String [] sig_figs = myfloat.split("(^0+(\\.?)0*|(~\\.)0+$|\\.)");
int sum = 0;
for (String fig : sig_figs)
{
sum += fig.length();
}
return sum;
I've since tried to convert it into a more Groovy-esque syntax to be compatible, and have produced the following:
def sum = 0;
def myint = toString(mynum);
def String[] sig_figs = myint.split(/[^0+(\\.?)0*|(~\\.)0+$|\\.]/);
for (int i = 0; i <= sig_figs.size();i++)
{
sum += sig_figs[i].length();
}
return(sum);
Note that 'mynum' is the parameter of the method
It should also be noted that this system has very little visibility in regards to what groovy functions are available in the system, so the solution likely needs to be as basic as possible
Any help would be greatly appreciated. Thanks!
I think this is the regex you need:
def num = '0.0120'
def splitted = num.split(/(^0+(\.?)0*|(~\.)0+$|\.)/)
def sf = splitted*.length().sum()
It's been a while since I've had to think about significant figures, so sorry if I have the wrong idea. But I've made two regular expressions that combined should count the number of significant figures (sorry I'm no regex wizard) in a string representing a decimal. It doesn't handle commas, you would have to strip those out.
This first regex matches all significant figures before the decimal point
([1-9]+\d*[1-9]|[1-9]+)
And this second regex matches all significant figures after the decimal point:
\.((\d*[1-9]+)+)?
If you add up the lengths of the first capture group (or 0 when no match) for both matches, then it should give you the number of significant figures.
Example:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SigFigs {
private static final Pattern pattern1 = Pattern.compile("([1-9]+\\d*[1-9]|[1-9]+)");
private static final Pattern pattern2 = Pattern.compile("\\.((\\d*[1-9]+)+)?");
public static int getSignificantFigures(String number) {
int sigFigs = 0;
for (int i=0; i < 2; i++) {
Matcher matcher = (i == 0 ? pattern1 : pattern2).matcher(number);
if (matcher.find()) {
try {
String s = matcher.group(1);
if (s != null) sigFigs += s.length();
} catch (IndexOutOfBoundsException ignored) { }
}
}
return sigFigs;
}
public static void main(String[] args) {
System.out.println(getSignificantFigures("0305.44090")); // 7 sig. figs
}
}
Of course using two matches is suboptimal (like I've said, I'm not crazy good at regex like some I could mention) but its fairly robust and readable

Making sure every Alphabet is in a string (Kotlin)

So I have a question where I am checking if a string has every letter of the alphabet in it. I was able to check if there is alphabet in the string, but I'm not sure how to check if there is EVERY alphabet in said string. Here's the code
fun isPangram (pangram: Array<String>) : String {
var panString : String
var outcome = ""
for (i in pangram.indices){
panString = pangram[i]
if (panString.matches(".^*[a-z].*".toRegex())){
outcome = outcome.plus('1')
}
else {outcome = outcome.plus('0')}
}
return outcome
}
Any ideas are welcomed Thanks.
I think it would be easier to check if all members of the alphabet range are in each string than to use Regex:
fun isPangram(pangram: Array<String>): String =
pangram.joinToString("") { inputString ->
when {
('a'..'z').all { it in inputString.lowercase() } -> "1"
else -> "0"
}
}
Hi this is how you can make with regular expression
Kotlin Syntax
fun isStrinfContainsAllAlphabeta( input: String) {
return input.lowercase()
.replace("[^a-z]".toRegex(), "")
.replace("(.)(?=.*\\1)".toRegex(), "")
.length == 26;
}
In java:
public static boolean isStrinfContainsAllAlphabeta(String input) {
return input.toLowerCase()
.replace("[^a-z]", "")
.replace("(.)(?=.*\\1)", "")
.length() == 26;
}
the function takes only one string. The first "replaceAll" removes all the non-alphabet characters, The second one removes the duplicated character, then you check how many characters remained.
Just to bounce off Tenfour04's solution, if you write two functions (one for the pangram check, one for processing the array) I feel like you can make it a little more readable, since they're really two separate tasks. (This is partly an excuse to show you some Kotlin tricks!)
val String.isPangram get() = ('a'..'z').all { this.contains(it, ignoreCase = true) }
fun checkPangrams(strings: Array<String>) =
strings.joinToString("") { if (it.isPangram) "1" else "0" }
You could use an extension function instead of an extension property (so it.isPangram()), or just a plain function with a parameter (isPangram(it)), but you can write stuff that almost reads like English, if you want!

How to Use Groovy to find the INTERSECTION of two lists?

I am trying to retrieve the common items across two lists using Groovy. The following code works just fine, i.e the output from running this code is "DEBUG found in common Items : same". So far so good!
def list1 = ["same", "different"]
def list2 = ["same", "not the same"]
def commonItems = list1.intersect(list2)
for(int i=0; i < commonItems.size(); i++)
{
log.info("DEBUG found in common Items : " + commonItems[i])
}
I hit an issue when I try to apply the above principle to a list of objects - my issue is that the 'commonItems' list does NOT contain the single object I would expect, but is empty. Please note, my custom object 'ErrorWarningDetail' does override compareTo. Can someone see what I am doing wrong / make any suggestions? Thanks in advance!
First of all here is my custom class - note 'CompateTo' just checks the 'Code' field for now.
class ErrorWarningDetail implements Comparable
{
public String Code
public String Description
public String ErrorType
public String State
#Override
int compareTo(Object o) {
int result = Code <=> o.Code
result
}
}
Now here is the code that does the business. I would expect one object to be in 'commonItems' but it is infact empty - what am i doing wrong here? The output of running this is "DEBUG no common items"
def similarONE = new ErrorWarningDetail()
similarONE.Code = "100-1"
def similarTWO =new ErrorWarningDetail()
similarTWO.Code = "100-1"
def completelyDifferent = new ErrorWarningDetail()
completelyDifferent.Code = "697-2"
def List1 = []
def List2 = []
List1.add(similarONE)
List1.add(completelyDifferent)
List2.add(similarTwo)
def commonItems = list1.intersect(list2)
if (commonItems.size() == 0)
{
log.info("DEBUG no common items")
}
Implementing compareTo() is not enough in Java, you should be implementing equals/hashCode instead.
In Groovy there's a handy annotation for that. So, the script down below executes successfully:
import groovy.transform.EqualsAndHashCode
#EqualsAndHashCode( includes = [ 'code' ] )
class ErrorWarningDetail implements Comparable {
String code
String description
String errorType
String state
#Override
int compareTo(Object o) {
code <=> ( o?.code ?: '' )
}
}
def similarONE = new ErrorWarningDetail( code:"100-1" )
def similarTWO = new ErrorWarningDetail( code:"100-1" )
def completelyDifferent = new ErrorWarningDetail( code:"697-2" )
def list1 = [similarONE, completelyDifferent]
def list2 = [similarTWO]
def commonItems = list1.intersect list2
assert 1 == commonItems.size()
P.S. Please, DO NOT name fields starting with Capital letters!
The equals and hashCode are the methods utilized to determine object equality, so the intersect method would rely on those.
The compareTo method is utilized for sorting purposes.
Groovy has some convenient utilities for common tasks in the package groovy.transform
Below is the modified class with the annotations that makes it work as intended.
#EqualsAndHashCode(includes=["Code"])
#ToString(includeFields=true)
class ErrorWarningDetail implements Comparable
{
String Code
String Description
String ErrorType
String State
#Override
int compareTo(Object o) {
Code <=> o?.Code
}
}

Get the first line of a string in haxe

Let's assume we have a multiline string, like
var s:String = "my first line\nmy second line\nmy third line\nand so on!";
What is the best way to get (only) the first line of this string in Haxe? I know I can do something like:
static function getFirstLine(s:String):String {
var t:String = s.split("\n")[0];
if(t.charAt(t.length - 1) == "\r") {
t = t.substring(0, t.length - 1);
}
return t;
}
However I'm wondering if there is any easier (predefined) method for this ...
Caveat that #Gama11's answer works well and is more elegant than this.
If your string is long, split will iterate over the whole thing and allocate an array containing every line in your string, both of which are unnecessary here. Another option would be indexOf:
static function getFirstLine(s:String):String {
var i = s.indexOf("\n");
if (i == -1) return s;
if (i > 0 && s.charAt(i - 1) == "\r") --i;
return s.substr(0, i);
}
There's no built-in utility in the standard library for this that I know of, but you make it a bit more elegant and avoid the substring() handling for \r by splitting on a regex:
static function getFirstLine(s:String):String {
return ~/\r?\n/.split(s)[0];
}
The regex \r?\n optionally matches a carriage return followed by a line feed character.

Grails convert String to Map with comma in string values

I want convert string to Map in grails. I already have a function of string to map conversion. Heres the code,
static def StringToMap(String reportValues){
Map result=[:]
result=reportValues.replace('[','').replace(']','').replace(' ','').split(',').inject([:]){map,token ->
List tokenizeStr=token.split(':');
tokenizeStr.size()>1?tokenizeStr?.with {map[it[0]?.toString()?.trim()]=it[1]?.toString()?.trim()}:tokenizeStr?.with {map[it[0]?.toString()?.trim()]=''}
map
}
return result
}
But, I have String with comma in the values, so the above function doesn't work for me. Heres my String
[program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]
my function returns ABC only. not ABC, INC. I googled about it but couldnt find any concrete help.
Generally speaking, if I have to convert a Stringified Map to a Map object I try to make use of Eval.me. Your example String though isn't quite right to do so, if you had the following it would "just work":
// Note I have added '' around the values.
​String a = "[program_type:'', subsidiary_code:'', groupName:'', termination_date:'', effective_date:'', subsidiary_name:'ABC']"
Map b = Eval.me(a)​
// returns b = [program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC]
If you have control of the String then if you can create it following this kind of pattern, it would be the easiest solution I suspect.
In case it is not possible to change the input parameter, this might be a not so clean and not so short option. It relies on the colon instead of comma values.
​String reportValues = "[program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]"
reportValues = reportValues[1..-2]
def m = reportValues.split(":")
def map = [:]
def length = m.size()
m.eachWithIndex { v, i ->
if(i != 0) {
List l = m[i].split(",")
if (i == length-1) {
map.put(m[i-1].split(",")[-1], l.join(","))
} else {
map.put(m[i-1].split(",")[-1], l[0..-2].join(","))
}
}
}
map.each {key, value -> println "key: " + key + " value: " + value}
BTW: Only use eval on trusted input, AFAIK it executes everything.
You could try messing around with this bit of code:
String tempString = "[program_type:11, 'aa':'bb', subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]"
List StringasList = tempString.tokenize('[],')
def finalMap=[:]
StringasList?.each { e->
def f = e?.split(':')
finalMap."${f[0]}"= f.size()>1 ? f[1] : null
}
println """-- tempString: ${tempString.getClass()} StringasList: ${StringasList.getClass()}
finalMap: ${finalMap.getClass()} \n Results\n finalMap ${finalMap}
"""
Above produces:
-- tempString: class java.lang.String StringasList: class java.util.ArrayList
finalMap: class java.util.LinkedHashMap
Results
finalMap [program_type:11, 'aa':'bb', subsidiary_code:null, groupName:null, termination_date:null, effective_date:null, subsidiary_name:ABC, INC:null]
It tokenizes the String then converts ArrayList by iterating through the list and passing each one again split against : into a map. It also has to check to ensure the size is greater than 1 otherwise it will break on f[1]

Resources