2

I have a String which contains some formatted content with LineFeed after each line. I want to format the content of that variable to restrict each line to have not more than 80 characters.

Can somebody help me with this in Groovy?

for testing purpose I copied the content in a file

String fileContents = new File('E://Projects//temp//license').text
println fileContents

fileContents content or Console Output

List of connectivities are:
    Valid [Metadata Exchange for Microsoft Visio]
   Valid [Metadata Exchange for Microstrategy]
   Valid [Metadata Exchange for Microsoft SQL Server Reporting Services and Analysis Services]
   Valid [Metadata Exchange for Netezza]
   Valid [Metadata Exchange for Oracle]
   Valid [Metadata Exchange for Oracle BI Enterprise Edition]
   Valid [Metadata Exchange for Oracle Designer]

Command ran successfully

Update

This is what I am using after tim_yates answer

def es=lic.entrySet()
xml.licInfo() {
    int i=0
    es.each{
        if(!it.key.contains("failed with error"))
        {
            String val=new String(it.value)
            license(name:it.key,value:trimOutput(val),assignedTo:resultRows[i++])

        }
    }       
}

def trimOutput(text)
{

    text=text.tokenize( '\n' )*.toList()*.collate(90)*.collect { it.join() }.flatten().join( '\n' )
    text
}

but is gives me the following exception

Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.collate() is applicable for argument types: (java.lang.Integer) values: [90]
Possible solutions: clone(), collect(groovy.lang.Closure), collect(groovy.lang.Closure), clear(), clear(), clear()

More update (console output of println es)

[license_all =Edition:          BAAC Standard
Software Version:  6.5
Distributed by:    ABC
Issued on:         2012-Feb-06
Validity period:   Non-Expiry
Serial number:     210502
Deployment level:  Production

List of supported platforms are:
   [All operating systems] is authorized for [100] logical CPUs
Number of authorized repository instances: 100
Number of authorized CAL usage count: 100

List of connectivities are:

   Valid [Metadata Exchange for Microsoft SQL Server Reporting Services and Analysis Services]
   Valid [Metadata Exchange for Netezza]
   Valid [Metadata Exchange for Oracle]
   Valid [Metadata Exchange for Oracle BI Enterprise Edition]
   Valid [Metadata Exchange for Oracle Designer]
   Valid [Metadata Exchange for Oracle Warehouse Builder]
   Valid [Metadata Exchange for Popkin System Architect]
   Valid [Metadata Exchange for SAP R/3]
   Valid [Metadata Exchange for Select SE]
   Valid [Metadata Exchange for Silverrun - RDM]
   Valid [Metadata Exchange for SQL Server]
   Valid [Metadata Exchange for Sybase ASE]
   Valid [Metadata Exchange for Sybase PowerDesigner]
   Valid [Metadata Exchange for Teradata]

Command ran successfully.
]

2 Answers2

2

Here's two different methods depending on what you want to do with lines over 80 chars in length

def text = '''List of connectivities are:
             |    Valid [Metadata Exchange for Microsoft Visio]
             |   Valid [Metadata Exchange for Microstrategy]
             |   Valid [Metadata Exchange for Microsoft SQL Server Reporting Services and Analysis Services]
             |   Valid [Metadata Exchange for Netezza]
             |   Valid [Metadata Exchange for Oracle]
             |   Valid [Metadata Exchange for Oracle BI Enterprise Edition]
             |   Valid [Metadata Exchange for Oracle Designer]
             |
             |Command ran successfully'''.stripMargin()

// Strip everything after 80 chars
println text.tokenize( '\n' )*.  // Split the lines based on newline character
             take( 80 ).         // Only take upto the first 80 chars of each String
             join( '\n' )        // And join them back together with '\n' between them

// Add newline if line is over 80 chars
println text.tokenize( '\n' )*.      // Split the lines based on newline character
             toList()*.              // Convert each String to a list of chars
             collate(80)*.           // Split these into multiple lists, 80 chars long
             collect { it.join() }.  // Join all of the chars back into strings
             flatten().              // Flatten the multiple lists of Strings into one
             join( '\n' )            // And join these strings back together with '\n' between them

Edit

After the edit, does this work:

String trimOutput( String input, int width=90 ) {
  input.tokenize( '\n' )*.
        toList()*.
        collate( width )*.
        collect { it.join() }.
        flatten().
        join( '\n' )
}

xml.licInfo {
  lic.eachWithIndex { key, value, idx ->
    // Shouldn't this be 'value', not 'key'?
    if( !key.contains( 'failed with error' ) ) {
      license( name: key, assignedTo: idx, trimOutput( value ) )
    }
  }
}

I think you need to change to checking for 'failed with error' in the value of the lic map, not the key as you have currently, but I can't be sure)


Edit2

If you are stuck with groovy 1.8.1, there is no collate method, so you'll have to roll your own:

List.metaClass.collate = { size ->
  def rslt = delegate.inject( [ [] ] ) { ret, elem ->
    ( ret.last() << elem ).size() >= size ? ret << [] : ret
  }
  !rslt.last() ? rslt[ 0..-2 ] : rslt
}
Community
  • 1
  • 1
tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • It looks so simple with groovy. Thanks –  Apr 25 '12 at 09:11
  • @Ricky no worries! Glad I could help, and have fun! :-) – tim_yates Apr 25 '12 at 09:12
  • My bad, the `text` comes in as a StringBuffer. It seems that `StringBuffer` does not have `tokenize` & my `text` is a StringBuffer, I tried `text.toString` but no luck –  Apr 25 '12 at 09:38
  • @Ricky what version of groovy? `assert new StringBuffer( 'this is a test' ).tokenize() == [ 'this', 'is', 'a', 'test' ]` works fine in 1.8.6 :-/ – tim_yates Apr 25 '12 at 09:51
  • @Ricky does that assert line pass? If not, can you edit your question so that it shows the actual situation you are facing, the code you are trying, and the exception thrown? – tim_yates Apr 25 '12 at 09:55
  • I updated my question with the code and exception. It's a standalone program so I just changed the groovy file, in my deployment folder –  Apr 25 '12 at 10:12
  • assignedTo is another list, so `idx` is not required, also now I get `Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.collate() is applicable for argument types: (java.lang.Integer) values: [90] Possible solutions: clone(), collect(groovy.lang.Closure), collect(groovy.lang.Closure), clear(), clear(), clear()` Exception :( –  Apr 25 '12 at 10:53
  • @Ricky Yeah, see __Edit2__ (upgrade to 1.8.6 would be better) ;-) – tim_yates Apr 25 '12 at 10:54
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/10488/discussion-between-tim-yates-and-ricky) – tim_yates Apr 25 '12 at 11:00
  • Hi, ataylor solution works but with just 1 small problem, it gives 2 line feeds in between sentences –  Apr 26 '12 at 10:53
1

Another solution using inject:

String trimOutput( String input, int width=90 ) {
    input.tokenize('\n')*.inject('') { output, ch ->
        output.size() % (width + 1) ?
            (output + ch) :
            (output + '\n' + ch)
    }.join('\n')
}

Or a combination of inject and collate:

String trimOutput( String input, int width=90 ) {
    input.tokenize('\n').inject([]) { lines, line ->
        lines + line.toList().collate(width)*.join()
    }.join('\n')
}
ataylor
  • 64,891
  • 24
  • 161
  • 189
  • It works just fine, with just 1 little problem, even after a new line encountered after a statement, it inserts another newline, so 2 Line feeds are there –  Apr 26 '12 at 10:53
  • @Ricky Try changing ` output.size() % (width + 1) ?` to ` ( output.size() + 1 ) % (width + 1) ?` – tim_yates Apr 26 '12 at 10:57
  • I changed accordingly, but still it there is a Line gap between 2 sentences (2 LF's, 1st for the next statement to be in the next line and 2nd is a blank new Line) –  Apr 26 '12 at 11:58