我想找到一个正则表达式(最好是在 Perl 中,但任何风格都可以)来替换每个 _
,除了那些前面有 8 位数字 和 后面有 6 位数字的代码。
实际上,我想替换文件名中的 _
,除了格式为 YYYYMMDD_hhmmss
的日期中的文件名。
一般来说,我想替换前面没有某种模式并且后面没有其他模式出现的某个字符。
我尝试了很多正则表达式并在网上查找了很多,但我没有找到任何东西!
我知道可以用 _
替换每个 .
,然后恢复 _
中的 YYYYMMDD.hhmmss
,但我有兴趣一步完成(希望这是可能的)。
以下是一些替换示例:
Patate_17890505_TitreEnCamelCase.ext --> Patate.17890505.TitreEnCamelCase.ext
EPFL_AlgebreLineaire --> EPFL.AlgebreLineaire
ipe.20210302_005606.pdf --> ipe.20210302_005606.pdf
1_ --> 1.
12_ --> 12.
_1 --> .1
_12 --> .12
12345678_ --> 12345678.
_123456 --> .123456
12345678_12345 --> 12345678.12345
1234567_123456 --> 1234567.123456
1234567_12345 --> 1234567.12345
123456_12345 --> 123456.12345
12345678_1234567 --> 12345678.1234567
123456789_123456 --> 123456789.123456
123456789_1234567 --> 123456789.1234567
_patate__truc__ --> .patate..truc..
___ --> ...
foo_12345678 --> foo.12345678
foo_12345678_123456_bar --> foo.12345678_123456.bar
12345678_123456 --> 12345678_123456
foo12345678_123456bar --> foo12345678_123456bar
下面是我尝试过的一些示例。
与我想要的完全相反,即替换每个 _
前面正好是 8 位数字,后面正好是 6 位数字(在 regex101 上尝试一下):
s/((?<!\d)(?:\d{8}))_((?:\d{6})(?!\d))/$1.$2/g
它有效,所以我需要这个正则表达式的否定......
只是负向回顾和负向超前(在 regex101 上尝试一下):
s/(?<!\d{8})_(?!\d{6})/./g
失败:如果 _
前面正好有 8 位数字或后面正好有 6 位数字,则不会替换,例如这些字符串中的 _
不会被替换:
12345678_
_123456
12345678_12345
1234567_123456
我需要替换除“and”之外的所有内容,但是这个替换除“or”之外的所有内容(因此它错过了一些 _
)。
灵感来自 this answer (来自 python regex: match a char surrounded by exactly 2 chars )(在 regex101 上尝试一下):
s/(?<!(?<!\d)\d{8})_(?!\d{6}(?!\d))/./g
失败:原因与上一个相同。
原始答案中的正则表达式有效,因为它替换了前面是前模式 和 后面是后模式的字符。
受到 this answer (来自 Replace character UNLESS surrounded by specific tag )的启发,但我不太明白它是如何工作的(在 regex101 上尝试一下):
s/_(?:(?!(?:.*?\d{6}))|(?=[^\d]+\d{8}))/./g
失败:在这些示例中,_
未被替换
_123456
1234567_123456
12345678_1234567
123456789_123456
123456789_1234567
foo_12345678
原来的问题与我的非常接近,但是前模式和后模式不是 \d{8}
和 \d{6}
,而是 HTML 标记,因此问题更容易: <tag>
和 </tag>
是独特的元素,对于我的问题,后-pattern \d{6}
后面可以跟一个其他数字(同样,预模式 \d{8}
前面可以跟一个其他数字)。
但这几乎可以工作,与之前的尝试不同,它替换了这两个字符串中的_
:
12345678_
12345678_12345
所以也许修改可以让它按照我想要的方式工作......
最佳答案
你可以使用
(?<!\d)\d{8}_\d{6}(?!\d)(*SKIP)(*F)|_
请参阅regex demo 。 详细信息:
-
(?<!\d)\d{8}_\d{6}(?!\d)
- 八位数字,_
以及未包含任何其他数字的六位数字 -
(*SKIP)(*F)
- 在当前位置匹配失败,并从失败位置继续正则表达式搜索 -
|
- 或 -
_
- 任何其他上下文中的下划线。
另一种正则表达式是
_(?!(?<=(?<!\d)\d{8}_)\d{6}(?!\d))
参见this regex demo 。 详细信息:
-
_
- 下划线 -
(?!(?<=(?<!\d)\d{8}_)\d{6}(?!\d))
- 如果出现以下情况,则表示匹配失败的负向前瞻 - 紧邻当前位置的右侧 - 紧接其后有六位(且不超过六位)数字,且前面正好有八位数字和下划线。
关于regex - 替换所有出现的字符,除非被两个不同的模式包围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71848318/