I need a Groovy method that finds all instances of a text occurrence and increments the value by one.
Given this multi line txt, comma delimited file:
AT,3,15,"Company Name","1 High Street","LONDON"," "," "," ","SE5 9AA"
TH,6,118316128,01,118316128,"HSYUD8292",19063,20220707,"4133339"," "," ","1800070",1,20220622,"SDD1880842M102580"
RE,6,13915,"10628","Retail Group US ","T/A Retail Group Illinois","Long Bridge Retail Park"
I have to match a number, in this case 118316128
and increment by 1 before writing back to the file. This number will always be different.
My method (with hardcoded test data for now) matches the first instance and successfully replaces it with 99999
Pattern IdPattern = Pattern.compile("(?<=TH,6,)[0-9] ");
def replaceIDs(sourcePath,IdPattern) {
def source = new File(sourcePath)
def text = source.text
source.withWriter {w ->
w << text.replaceAll(IdPattern), "99999"} //"99999" is dummy text for now
}
Is there a neat way of matching both instances and incrementing by one so 118316128
becomes 118316129
in both occurrences?
I am learning Groovy so be gentle :)
CodePudding user response:
Good news! You don't need a regex, depending on your use case. If it is a once-off replacement of one string with another, you can do it with
yourString.replaceAll("118316128,", "118316129,")
If you will be doing this a lot, I would read each line into a list and then replace the list elements with the new values.
Option three is using a CSV reader to manipulate the data as rows and columns.
The last option is to use a regex.
CodePudding user response:
I would use a full power of java's Pattern/Matcher functionality and put it this way:
String csv = '''\
AT,3,15,"Company Name","1 High Street","LONDON"," "," "," ","SE5 9AA"
TH,6,118316128,01,118316128,"HSYUD8292",19063,20220707,"4133339"," "," ","1800070",1,20220622,"SDD1880842M102580"
TH,6,118317000,01,118317000,"HSYUD8292",19063,20220707,"4133339"," "," ","1800070",1,20220622,"SDD1880842M102580"
TH,6,118318000,01,118319000,"HSYUD8292",19063,20220707,"4133339"," "," ","1800070",1,20220622,"SDD1880842M102580"
RE,6,13915,"10628","Retail Group US ","T/A Retail Group Illinois","Long Bridge Retail Park"'''
def matcher = csv =~ /,(\d{9,20}),/
StringBuffer sb = new StringBuffer()
while( matcher.find() ){
int incNum = matcher.group()[ 1..-2 ].toInteger() 1
matcher.appendReplacement sb, ',' incNum ','
}
matcher.appendTail sb
sb
and the sb
is as follows:
AT,3,15,"Company Name","1 High Street","LONDON"," "," "," ","SE5 9AA"
TH,6,118316129,01,118316129,"HSYUD8292",19063,20220707,"4133339"," "," ","1800070",1,20220622,"SDD1880842M102580"
TH,6,118317001,01,118317001,"HSYUD8292",19063,20220707,"4133339"," "," ","1800070",1,20220622,"SDD1880842M102580"
TH,6,118318001,01,118319001,"HSYUD8292",19063,20220707,"4133339"," "," ","1800070",1,20220622,"SDD1880842M102580"
RE,6,13915,"10628","Retail Group US ","T/A Retail Group Illinois","Long Bridge Retail Park"
You may want to adjust the regex to include/exclude numbers.
CodePudding user response:
An example using commons-csv. You can use any stream for input and output.
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVPrinter
import org.apache.commons.csv.CSVRecord
import spock.lang.Specification
class CSVTest extends Specification {
void processCSV(Reader inputStream, Appendable outputStream, String fromNumber, String toNumber) {
CSVPrinter csvPrinter = new CSVPrinter(outputStream, CSVFormat.DEFAULT)
Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(inputStream)
for (CSVRecord record: records) {
List<String> values = record.toList()
for (int i = 0; i < values.size(); i ) {
if (values.get(i) == fromNumber) {
values.set(i, toNumber)
}
}
csvPrinter.printRecord(values)
}
}
def 'replace CSV number'() {
given:
String input = """\
111,"2",2,222,333\r
444,222,2,"2,2,",555\r
"""
String expectedOutput = """\
111,3,3,222,333\r
444,222,3,"2,2,",555\r
"""
String fromNumber = '2'
String toNumber = '3'
Reader inputStream = new StringReader(input)
Appendable outputStream = new StringBuffer()
when:
processCSV(inputStream, outputStream, fromNumber, toNumber)
then:
expectedOutput == outputStream.toString()
}
}