sed 在两个或多个大写字母之间添加点,并且大写字母后面不跟小写字母

sed add dots between two or more capitals and capitals not followed by lower case letter

提问人:coffee9000 提问时间:11/10/2023 最后编辑:tripleeecoffee9000 更新时间:11/10/2023 访问量:56

问:

我需要有关 sed 的帮助

两个命令

  1. 在两个或多个大写字母之间添加点
  2. 大写字母后面没有小写字母。

我正在尝试任何两个或多个大写字母在它们之间有点。

我想转换

A
[BC]
XYZ

A
[B.C.]
X.Y.Z.

我最接近的是

echo "abcd Abcd ABcd ABCd ABCD" |
sed -e "s/[A-Z]\{2\}/&./g"

产生

abcd Abcd AB.cd AB.Cd AB.CD.</sub>

如果更容易,另一个单独的命令可以在任何没有后跟小写字母的大写字母之间添加一个点。

Ab
[A]
D6
FGH
X"

Ab
[A.]
D.6.
F.G.H.
X."

我得到的最接近的:

echo "abcd Abcd ABcd ABCd ABCD" |
sed -e "s/[A-Z][^a-z]/&./g"

产生

abcd Abcd AB.cd AB.Cd AB.CD.
正则表达式 SED

评论

0赞 coffee9000 11/10/2023
更接近但失败了 “ABCd” > “A.B.Cd” 应该是“A.B.C.D”......echo “AbcdABCddABCDe” |sed “s/([A-Z])([A-Z])/\1\2./g;s//\1.\2/g”
0赞 jhnc 11/10/2023
如果大写字母后面已经跟着一个点怎么办? 应该变成 ?A.A..
0赞 jhnc 11/10/2023
为什么是第一而不是?A [B.C.] X.Y.Z.A [B.C] X.Y.Z
0赞 jhnc 11/10/2023
为什么是第二而不是?Ab [A.] D.6. F.G.H. X."Ab [A.] D.6 F.G.H. X."
0赞 Mark Reed 11/10/2023
为什么在示例中,在 6 之后加一个点?6 不是大写字母。

答:

1赞 jhnc 11/10/2023 #1

传统上,一旦找到与正则表达式匹配的文本,该文本就会被使用,并且不会考虑进行进一步的匹配。无法进行重叠匹配。为了解决这个问题,一些正则表达式引擎支持环视断言(look-ahead/look-behind),这些断言匹配但不使用文本。

标准正则表达式没有复杂的环视功能,因此功能不够强大,无法一次性完成此操作。它需要某种循环,以允许将已消耗的文本重新用于更多匹配尝试。sed


两个或多个大写字母(彼此相邻)之间有点:

$ echo 'A [BC] XYZ' | sed '
    :a
    s/\([A-Z]\)\([A-Z]\)/\1.\2/g
    ta
'
A [B.C] X.Y.Z
$

在不跟小写字母的任何大写字母之间添加一个点:

$ echo 'Ab [A] D6 FGH W.X"Z' | sed '
    :a
    s/\([A-Z]\)\([^\na-z]\|$\)/\1\n\2/g
    ta
    y/\n/./
'
Ab [A.] D.6 F.G.H. W..X."Z.
$

第二个命令假定大写字母后面的点或换行符计为 “非小写字母”,因此执行中间替换以确保循环终止。


其他一些正则表达式引擎更强大。

例如,使用 Perl 正向和负向前瞻断言:

$ echo 'A [BC] XYZ' | perl -pe 's/([A-Z])(?=[A-Z])/$1./g'
A [B.C] X.Y.Z
$
$ echo 'Ab [A] D6 FGH W.X"Z' | perl -pe 's/([A-Z])(?![a-z])/$1./g'
Ab [A.] D.6 F.G.H. W..X."Z.
$ 

评论

0赞 coffee9000 11/10/2023
我犯了错误,一切都很好。谢谢。它们都根据需要工作。
0赞 jhnc 11/15/2023
为了便携性,请勿在 的替换部分使用 。请改用反斜杠,后跟文字换行符\ns///
0赞 Mark Reed 11/10/2023 #2

任何大写字母后跟另一个大写字母后自动不会跟小写字母,因此它应该在第二条规则中得到一个点。第一条规则不会添加任何内容。

几乎有效:

sed 's/\([A-Z]\)\([^a-z]\)/\1.\2/g'

但它不会将第二个字符视为重叠匹配中的第一个字符的可能候选者,即使它是大写字母。因此,Perl 前瞻断言更好:

perl -pe 's/([A-Z])(?![a-z])/$1./g'