简体   繁体   English

如何在Java中替换字符串的一部分,它匹配第一个字符,转义中间的一些字符并匹配最后的一些字符?

[英]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.我正在研究一个 Java,它对 SQL 文件进行了一些更改并将其转换为 Oracle 兼容格式。

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.似乎要更改 Timestamp\\date 值,我需要使用 oracle 函数“To_TIMESTAMP”将其更改为某种 oracle 可理解的格式。

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.我只'2017-03-08 10:59:31' '2017-03-08 10:59:41''2017-03-08 10:59:41'并且这些值可能出现 2 次以上。 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')我想将它们更改\\替换为To_TIMESTAMP('2017-03-08 10:59:31','YYYY-MM-DD HH24:MI:SS')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.它替换到To_TIMESTAMP('2017-03-08 10:59:31' ,但我不知道该如何结束部分取代'2017-03-08 10:59:31''2017-03-08 10:59:31','YYYY-MM-DD HH24:MI:SS')任何帮助将不胜感激。 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 JDBC 4.2

As of JDBC 4.2, we can directly exchange java.time objects with the database.从 JDBC 4.2 开始,我们可以直接与数据库交换java.time对象。 No need to mess with passing strings, or using regex, or calling the Oracle TO_TIMESTAMP function.无需处理传递字符串、使用正则表达式或调用 Oracle TO_TIMESTAMP函数。

LocalDateTime

For your inputs such as 2017-03-08 10:59:31 , use LocalDateTime .对于诸如2017-03-08 10:59:31类的输入,请使用LocalDateTime This class represents a date and a time-of-day lacking any concept of time zone or offset-from-UTC.此类表示缺乏任何时区或UTC 偏移量概念的日期和时间。 As such, it is appropriate for database columns of a data type akin to the SQL-standard type TIMESTAMP WITHOUT TIME ZONE .因此,它适用于数据类型类似于 SQL 标准类型TIMESTAMP WITHOUT TIME ZONE数据库列。

ISO 8601 ISO 8601

Your input strings nearly comply with the ISO 8601 standard.您的输入字符串几乎符合ISO 8601标准。 Replace the SPACE character in the middle with a T to fully comply.T替换中间的空格字符以完全符合。 The java.time class use these standard formats by default when parsing/generating strings. java.time类在解析/生成字符串时默认使用这些标准格式。 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关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于 Java 8 及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar ,和SimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial .要了解更多信息,请参阅Oracle 教程 And search Stack Overflow for many examples and explanations.并在 Stack Overflow 上搜索许多示例和解释。 Specification is JSR 310 .规范是JSR 310

You may exchange java.time objects directly with your database.您可以直接与您的数据库交换java.time对象。 Use a JDBC driver compliant with JDBC 4.2 or later.使用符合JDBC 4.2或更高版本的JDBC 驱动程序 No need for strings, no need for java.sql.* classes.不需要字符串,不需要java.sql.*类。

Where to obtain the java.time classes?从哪里获得 java.time 类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目用额外的类扩展了 java.time。 This project is a proving ground for possible future additions to java.time.该项目是未来可能添加到 java.time 的试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more .您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

You might get better performance using a StringBuilder for the output, but here is the basic idea vis-a-vis the regular expression:使用 StringBuilder 作为输出可能会获得更好的性能,但这里是与正则表达式相比的基本思想:

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:替换在字符串中可能出现可变次数的模式的习惯用法取自Matcher.appendReplacement的文档,是:

    // '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')) (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'不替换无效的日期时间 '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') (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.仅供参考$0整个比赛的替换反向参考。


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'))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java String#contains() 使用带有转义字符的 String#matches() - Java String#contains() using String#matches() with escape character 如何在java中的字符之间使用包含。*的字符串.matches - How to use .matches for string containing .* in between characters in java JAVA:如何在嵌套的 JSONString 中查找 substring 的所有匹配项并替换为一些文本 - JAVA: How to find all matches of a substring in a nested JSONString and replace with some text 使用正则表达式将字符串分割成一些字符和转义序列 - splitting a string in between some characters and escape sequences using a regex expression 如果某些条件在 Java 8 中匹配,如何从 forEach 退出 - How to exit from forEach if some condition matches in java 8 Java-转义HTML字符(不包括某些字符) - Java - Escape HTML characters excluding some characters 如何替换字符串的某些字符 - how to replace some character's of String 如何用某些字符或字符串替换重复的字符 - How to replace a repeated char with some characters or string Java8流式处理如何用其他字符列表替换特定字符列表 - Java8 streams how to replace a particular list of character with some other list of characters 如何为带有转义字符的String.matches()创建正则表达式? - How do I properly create a regex for String.matches() with escape characters?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM