如何匹配不在4的倍数中的空格?

6 投票
3 回答
3714 浏览
提问于 2025-04-18 17:22

我正在用notepad++重新格式化一个Python脚本,但有些行的缩进不是4个(或者8、12、16等)空格。

所以我需要找到连续的开头空格(也就是每行开头的缩进),这些空格不是4的倍数,也就是说,空格的数量是1、2、3、5、6、7、9、10、11等等。

例如:

>>>   a = 1      # match this, as there're 3 spaces at the beginning
>>>       b = a  # match this too, as indent by 7 spaces
>>>    c = 2     # but not this, since it's indented exactly by 4 spaces
>>>        d = c # not this either, since indented by 8 spaces

我能用类似这样的方式找到4的倍数的空格:

^( {16}| {12}| {8}| {4})

然后我试着用类似这样的方式找到相反的情况:

^[^( {16}| {12}| {8}| {4})]

但这样只匹配到空行或者以字符开头的行,并不是我想要的。

我对正则表达式完全是个新手,但我搜索了几个小时也没找到解决办法。我知道我可以直接列出所有不是4的倍数的数字来匹配,但我希望能有人帮我提供一个更简单的方法。

谢谢。

更新 1

使用正则表达式(@user2864740)

^(?:\s{4})*\s{1,3}\S

或者(@alpha bravo)

^(?!(\s{4})+\S)(.*)

可以匹配不是4的倍数的缩进,以及有4个(8、16等)空格的空行和紧接着的第一个非空行的第一个字符。

例如(在regex101.com上)

如何避免匹配上面例子中描述的这些情况?

3 个回答

1

你可以使用这个模式^(?!(\s{4})+\S)(.*)来实现某些功能。这里有个示例

3

我可以提供一个Python脚本,它可以告诉你哪些行的缩进不正确:

with open('path/to/code/file') as infile:
    for i,line in enumerate(infile,1):
        total = len(line)
        whitespace = total-len(line.lstrip(' '))
        if whitespace%4:
            print("Inconsistent indenting on line", i)
12

字符类只能包含一组特定的字符,所以像 [^..] 这样的写法不适合用来表示一般的否定。正则表达式 [^( {16}| {12}| {8}| {4})] 的意思是和 [^( {16}|284] 是一样的,它会匹配所有没有列出的 字符

现在,要匹配 不是 4 的倍数的空格,其实就是在找 n mod 4 = {1, 2, 3}(或者说 除了 n mod 4 = 0)的空格。我们可以用下面这样的模式来实现:

(?:\s{4})*\s{1,3}\S

解释:

(?:\s{4})*  - match any number of whole groups of 4 spaces and then ..
\s{1,3}     - match any count of 1, 2, or 3 spaces such that ..
\S          - they are not followed by a space

根据使用的情况,正则表达式可能需要在后面加一个点号通配符 .*,或者在前面加一个行锚点 ^

撰写回答