简体   繁体   中英

How to replace part of a string in Java, where it matches 1st few characters, escape some in between and matches some character at the end?

I'm working on a Java which does some changes to an SQL file and covert it to an Oracle competible format.

It seems for changing the Timestamp\\date values, I need to use an oracle function "To_TIMESTAMP" to change it to some oracle understandable formart.

Now to the real question. Below I have a String line;

(1,'Ctx_Log-Log','','08.03.2017','2017-03-08 10:59:31','10:59:32','2017-03-08 10:59:41')

where I'm interested in only values like '2017-03-08 10:59:31' and '2017-03-08 10:59:41' and these value can occur more than 2 times. I want to change\\replace them to To_TIMESTAMP('2017-03-08 10:59:31','YYYY-MM-DD HH24:MI:SS') and To_TIMESTAMP('2017-03-08 10:59:41','YYYY-MM-DD HH24:MI:SS')

and I don't want to disturb the other values. I tried to regex solution, but I could only match and replace the start of the string, like

string.replaceAll(",'201", ",To_TIMESTAMP('201")

which replace it to To_TIMESTAMP('2017-03-08 10:59:31' but I don't know how to replace the end part of '2017-03-08 10:59:31' to '2017-03-08 10:59:31','YYYY-MM-DD HH24:MI:SS') Any help will be appreciate. It doesn't matter which way or method is performed, as far as gives me the right solution. Thanks

A simple way to do the trick is:

public static void main(String[] args) {
   String text = "(1,'Ctx_Log-Log','','08.03.2017','2017-03-08 10:59:31','10:59:32','2017-03-08 10:59:41')";
   String regex = "'[0-9]{4}-[0-9]{2}-[0-9]{2}\\s[0-9]{2}:[0-9]{2}:[0-9]{2}'";
   String template = "TO_TIMESTAMP(%s,'YYYY-MM-DD HH24:MI:SS')";

   Matcher matcher = Pattern.compile(regex).matcher(text);

   while (matcher.find()) {
       String value = matcher.group();
       text = text.replace(value, String.format(template, value));
   }

   System.out.println(text);
}

Smart objects, not dumb strings

Why use mere text when you can use objects to communicate with your database?

JDBC 4.2

As of JDBC 4.2, we can directly exchange java.time objects with the database. No need to mess with passing strings, or using regex, or calling the Oracle TO_TIMESTAMP function.

LocalDateTime

For your inputs such as 2017-03-08 10:59:31 , use LocalDateTime . This class represents a date and a time-of-day lacking any concept of time zone or offset-from-UTC. As such, it is appropriate for database columns of a data type akin to the SQL-standard type TIMESTAMP WITHOUT TIME ZONE .

ISO 8601

Your input strings nearly comply with the ISO 8601 standard. Replace the SPACE character in the middle with a T to fully comply. The java.time class use these standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.

Example code

String input = "(1,'Ctx_Log-Log','','08.03.2017','2017-03-08 10:59:31','10:59:32','2017-03-08 10:59:41')";
String inputModified = input.substring( 1 , input.length()-1 ) ;  // Remove parens at front and back. In real work, I would check that they are indeed parens.
String[] parts = inputModified.split( "," );
for ( String part : parts ) {
    if( part.length()==21 ) { // Possibly a date-time value we are targeting.
        String s = part.replace( "'" , "" ); // Remove quote marks.
        s = s.replace( " " , "T" );  // To comply with ISO 8601 standard, replace the SPACE in the middle with a `T`.
        try {
            LocalDateTime ldt = LocalDateTime.parse(s); // Convert string such as `2018-01-23T01:23:45` to a date-time object lacking any concept of time zone or offset-from-UTC.
            …
            myPreparedStatement.setObject( … , ldt ) ;
            …
        } catch ( DateTimeParseException e ) {
            // Unexpected input.
            e.printStackTrace();
        }
    }
}

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.

To learn more, see the Oracle Tutorial . And search Stack Overflow for many examples and explanations. Specification is JSR 310 .

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more .

You might get better performance using a StringBuilder for the output, but here is the basic idea vis-a-vis the regular expression:

String input = "(1,'Ctx_Log-Log','','08.03.2017','2017-03-08 10:59:31','10:59:32','2017-03-08 10:59:41')";
Pattern regex = Pattern.compile("('[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}')" );
Matcher m = regex.matcher(input);
while (m.find()) {
    input = input.replace(m.group(), String.format("TO_TIMESTAMP(%s,'YYYY-MM-DD HH24:MI:SS')", m.group()));
}
System.out.printf("%s\n", input);

The idiom for replacing a pattern that may occur a variable number of times in a string is, taken from the documentation of Matcher.appendReplacement , is:

    // '2017-03-08 10:59:31'
    Pattern dateTimePattern = Pattern.compile("'\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}'");
    Matcher dateTimeMatcher = dateTimePattern.matcher("(1,'Ctx_Log-Log','',"
            + "'08.03.2017','2017-03-08 10:59:31','10:59:32','2017-03-08 10:59:41')");
    StringBuffer result = new StringBuffer();
    while (dateTimeMatcher.find()) {
        dateTimeMatcher.appendReplacement(result, "To_TIMESTAMP(" + dateTimeMatcher.group() + ')');
    }
    dateTimeMatcher.appendTail(result);
    System.out.println(result.toString());

The output from this snippet is:

(1,'Ctx_Log-Log','','08.03.2017',To_TIMESTAMP('2017-03-08 10:59:31'),'10:59:32',To_TIMESTAMP('2017-03-08 10:59:41'))

If that were me I would want to add a further validation of the date-time string to make sure I don't replace something that just looked like a date-time:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("''uuuu-MM-dd HH:mm:ss''");
    Pattern dateTimePattern = Pattern.compile("'\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}'");
    // 2017-77-77 77:77:77 is not a valid date-time and should not be replaced.
    Matcher dateTimeMatcher = dateTimePattern.matcher("(1,'Ctx_Log-Log','',"
            + "'08.03.2017','2017-03-08 10:59:31','10:59:32','2017-77-77 77:77:77')");
    StringBuffer result = new StringBuffer();
    while (dateTimeMatcher.find()) {
        String old = dateTimeMatcher.group();
        try {
            // For validation try to parse the string.
            LocalDateTime.parse(old, dtf);
            dateTimeMatcher.appendReplacement(result, "To_TIMESTAMP(" + old + ')');
        } catch (DateTimeParseException dtpe) {
            // Validation failed, this was not a date-time.
            System.err.println("Not replacing invalid date-time " + old);
            // To avoid changing anything replace the string with itself.
            dateTimeMatcher.appendReplacement(result, old);
        }
    }
    dateTimeMatcher.appendTail(result);
    System.out.println(result.toString());

Not replacing invalid date-time '2017-77-77 77:77:77'

(1,'Ctx_Log-Log','','08.03.2017',To_TIMESTAMP('2017-03-08 10:59:31'),'10:59:32','2017-77-77 77:77:77')

Here's a one liner:

input = input.replaceAll("'\\d{4}(-\\d\\d){2} \\d\\d(:\\d\\d){2}'", "To_TIMESTAMP($0,'YYYY-MM-DD HH24:MI:SS')");

FYI $0 is a replacement back-reference for the entire match.


Some test code:

String input = "(1,'Ctx_Log-Log','','08.03.2017','2017-03-08 10:59:31','10:59:32','2017-03-08 10:59:41')";
input = input.replaceAll("'\\d{4}(-\\d\\d){2} \\d\\d(:\\d\\d){2}'", "To_TIMESTAMP($0, 'YYYY-MM-DD HH24:MI:SS')");
System.out.println(input);

Output:

(1,'Ctx_Log-Log','','08.03.2017',To_TIMESTAMP('2017-03-08 10:59:31', 'YYYY-MM-DD HH24:MI:SS'),'10:59:32',To_TIMESTAMP('2017-03-08 10:59:41', 'YYYY-MM-DD HH24:MI:SS'))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM