我有很多带有 XML 格式的日期的文本文件,格式如下:
<DATA2020-04-13T08:59:05.427 />
需要改成这样:
<DATA>2020-04-13T08:59:05.427</DATA>
笔记:
日期和时间因字符串而异,并且不能更改。每行中该字符串之前和之后都有更多 XML 格式的内容。另外,使用 Unixdate
也不是一个选择,我确实需要更改文件内的 XML 字符串。
我正在考虑使用sed
//查找和替换awk
,perl
也许使用通配符。谁能想出一种方法来实现这一目标吗?
答案1
$ echo '<DATA2020-04-13T08:59:05.427 />' | sed -E 's/<DATA(20[^/]*) \/>/<DATA>\1<\/DATA>/'
<DATA>2020-04-13T08:59:05.427</DATA>
或者,使用=
代替 作为分隔符/
,以避免必须反斜杠转义 s /
:
$ echo '<DATA2020-04-13T08:59:05.427 />' | sed -E 's=<DATA(202[^/]*) />=<DATA>\1</DATA>='
<DATA>2020-04-13T08:59:05.427</DATA>
这使得它更容易阅读(当然,您现在必须转义=
搜索模式和替换文本中的任何字符)。
您也可以在 perl 中使用几乎相同的正则表达式(主要区别在于,虽然\1
在 perl 中工作以引用捕获组,但使用 更好且更正确$1
),它有更多用于分隔s
运算符的选项,例如匹配对{
和}
:
$ echo '<DATA2020-04-13T08:59:05.427 />' |
perl -pe 's{<DATA(202[^/]*) />}
{<DATA>$1</DATA>}'
<DATA>2020-04-13T08:59:05.427</DATA>
perl 还有一个/x
修饰符来忽略未使用括号表达式转义或未\
在括号表达式中转义的空格(包括换行符)。它也忽略#
评论。目的是让您能够更轻松地在代码中编写更具可读性、记录在案的正则表达式。
man perlre
有关 perl 正则表达式的详细信息,请参阅参考资料。
答案2
使用支持 ERE 的 sed -E
(例如 GNU 或 BSD sed):
$ sed -E 's:<(DATA)([^ ]+) />:<\1>\2</\1>:' file
<DATA>2020-04-13T08:59:05.427</DATA>
否则,在每个 Unix 机器上的任何 shell 中使用任何 sed:
$ sed 's:<\(DATA\)\([^ ]*\) />:<\1>\2</\1>:' file
<DATA>2020-04-13T08:59:05.427</DATA>
答案3
使用乐(以前称为 Perl_6)
raku -pe 's:g/ \<DATA ( <+[0..9]+[-T:.]>+ ) \s\/\> /{"<DATA>"~$0~"</DATA>"}/;'
或者
raku -pe 's:g[ "<DATA" ( <+[0..9]+[-T:.]>+ ) " />" ] = ["<DATA>"~$0~"</DATA>"];'
输入示例:
<DATA2020-04-13T08:59:05.427 />
示例输出:
<DATA>2020-04-13T08:59:05.427</DATA>
以上是编码的答案乐,Perl 编程语言家族的成员。上面的两个例子都有四个值得注意的一般特征:
无需猜测反斜杠字符:如果不是
<alnum>
(字母数字或下划线),则需要转义,/g
像现在这样的正则表达式修饰符位于紧随 之后的表单global
开头,前面有一个冒号。要么或有效,s///
s
s:global
s:g
Perl 的
/x
修饰符现在是 Raku 中的默认设置(允许正则表达式原子之间有自由的空格),并且Raku 中的字符串连接是通过
~
波浪号完成的。
上面的两个示例都使用枚举字符类<+[0..9]+[-T:.]>
,它非常简单地由数字 [ 0..9
] 加上四个字符 [ -
T
:
.
] 组成。此外,虽然上面的第一个示例遵循传统的s///
替换习惯用法,但上面的第二个示例使用 Raku 的新“无反斜杠”替换格式(=
中间有等号),一些读者可能会发现这种格式更具可读性。
最后,如果您对日期时间提取/修改有兴趣,Raku 可以满足您的需求:
~$ echo '<DATA2020-04-13T08:59:05.427 />' | raku -pe 's:g[ "<DATA" ( <+[0..9]+[-T:.]>+ ) " />" ] = [DateTime($0~"Z")];'
2020-04-13T08:59:05.427000Z
~$ echo '<DATA2020-04-13T08:59:05.427 />' | raku -pe 's:g[ "<DATA" ( <+[0..9]+[-T:.]>+ ) " />" ] = [DateTime(now) - DateTime($0~"Z")];'
54862286.622457
https://docs.raku.org/language/regexes#Enumerated_character_classes_and_ranges
https://docs.raku.org/routine/DateTime
https://raku.org