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

5
我正在使用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

我能够用类似以下的方法匹配多个四个空格:

^( {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上)

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


^(?!\s{16}|\s{12}|\s{8}|\s{4}).* - hjpotter92
使用vim,:set shiftroundgg>G<G:wq,完成。 - Eevee
@Eevee 这就是为什么我从来没有真正尝试学习vim D: - user2864740
@hjpotter92 这个符合我描述的条件,而且行开头不是空格字符,还有空行。 - H S
@user2864740 你不能告诉我这比问题和答案中的正则表达式更不可理喻 :) (它将整个文件缩进一个级别,然后取消缩进。shiftround 强制缩进命令始终缩进到制表符停止的倍数,即使该行之前未对齐。) - Eevee
3个回答

11

字符类只能包含一组字符,因此[^..]不适用于通用否定。正则表达式[^( {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

根据使用情况,正则表达式可能需要一个尾随点通配符 (.*) 或前导行锚定符 (^)。


符合我所描述的内容。还要匹配空行和其后第一行的第一个非空字符。有关更多详细信息,请参见帖子中的更新1 - H 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)

我很欣赏@user2864740的纯正则表达式解决方案,但是正则表达式经常被用作字符串匹配的终极解决方案。这个基于lstrip的解决方案简短、简洁,非常易懂。一个真正的基于正则表达式的解决方案本质上更加复杂。 - Jonathan Eunice
Python确实可以更加直接地完成这个任务。然而我认为这有点过度设计,因为我可以用一行正则表达式来完成“查找”(只要脚本本身没有太多匹配项)。但是感谢您提供这个方法。 - H S

1
你可以使用这个模式^(?!(\s{4})+\S)(.*)演示,它与编程有关。请注意,不要删除HTML标签并使内容更加易懂。

很好。记得加一点解释。此外,我认为 (\s{4})* 可能更合适,这样 no_ident = foo 就不会被匹配。 - user2864740

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接