如何在 Java 中替换字符串的一部分,其中它匹配第 1 个字符,转义中间的一些字符并在末尾匹配某个字符?



我正在开发一个Java,它对SQL文件进行一些更改并将其转换为Oracle竞争格式。

似乎为了更改时间戳\日期值,我需要使用预言机函数"To_TIMESTAMP"将其更改为一些预言机可理解的形式。

现在进入真正的问题。下面我有一条字符串线;

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

我只对'2017-03-08 10:59:31''2017-03-08 10:59:41'等值感兴趣,这些值可以出现 2 次以上。我想将它们更改\替换为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')

我不想打扰其他价值观。我尝试使用正则表达式解决方案,但我只能匹配和替换字符串的开头,例如

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

将其替换为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')任何帮助将不胜感激。执行哪种方式或方法并不重要,只要给我正确的解决方案。谢谢

一个简单的方法是:

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);
}

智能对象,而不是哑字符串

当您可以使用对象与数据库通信时,为什么要仅使用文本?

JDBC 4.2

从 JDBC 4.2 开始,我们可以直接与数据库交换java.time对象。无需弄乱传递字符串,或使用正则表达式或调用OracleTO_TIMESTAMP函数。

LocalDateTime

对于输入(如2017-03-08 10:59:31),请使用LocalDateTime。此类表示日期和时间,缺少任何时区概念或 UTC 偏移量。因此,它适用于数据类型类似于 SQL 标准类型TIMESTAMP WITHOUT TIME ZONE的数据库列。

ISO 8601

认证您的输入字符串几乎符合 ISO 8601 标准。将中间的空格字符替换为完全符合Tjava.time类在解析/生成字符串时默认使用这些标准格式。因此,无需指定格式模式。

示例代码

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();
}
}
}

关于java.time

java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧传统日期时间类,如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到 java.time 类。

要了解更多信息,请参阅Oracle 教程。并搜索堆栈溢出以获取许多示例和解释。规范为 JSR 310。

您可以直接与数据库交换java.time对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获得java.time类?

Java SE 8、Java SE 9、Java SE
  • 10、Java SE 11及更高版本 - 标准 Java API 的一部分,具有捆绑实现。
    • Java 9添加了一些小功能和修复。
  • Java SE 6 和 Java SE 7 大部分
    • java.time 功能在ThreeTen-Backport中向后移植到 Java 6 和 7。
  • Android
    • 更高版本的java.time类的 Android 捆绑实现。
    • 对于早期的Android(<26),ThreeTenABP项目适应了ThreeTen-Backport(如上所述)。请参阅如何使用ThreeTenABP...

ThreeTen-Extra项目通过额外的类扩展了java.time。这个项目是未来可能添加到java.time的试验场。你可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等。

使用 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("%sn", input);

替换字符串中可能出现可变次数的模式的习惯用语是,取自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());

此代码段的输出为:

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

如果是我,我想添加日期时间字符串的进一步验证,以确保我不会替换看起来像日期时间的内容:

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());

不替换无效的日期时间 '2017-77-77 77:77:77'

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

这是一个行:

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

仅供参考$0整个比赛的替换反向参考。


一些测试代码:

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

输出:

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

最新更新