如何在没有 else 的情况下找到所有 if 语句?

How can I find all if-statements without an else?

我有很多代码,其中有时写了 if 语句,但没有匹配的 else 语句。在某些地方,这是一个问题,因为当出现故障时,故障没有得到正确处理。我想手动确认所有发生 if-without-an-else 的地方。

我试过使用正则表达式,但我没有成功找到匹配右括号的方法,因为正则表达式 cannot really handle nested brackets.

我要查找的代码如下所示:

if( ... ) {

...

}

我不想找到的代码,看起来像这样:

if( ... ) {

...

} 
else {

... 

}

如何列出所有这些地点,以便我浏览它们?

正如您自己注意到的,通常这必须使用某种解析器来完成。使用正则表达式简直就是痛苦,那里有很多解析器/语法模块。

我创建了一个一次性解决方案脚本(在 nodejs 中),它使用正则表达式和缩进数来匹配开始到结束 if / else 语句。如果满足以下条件,它会起作用:

  • 文件格式正确,开头 if 与结尾 else
  • 的缩进数相同

这个有效:

if(a) {
   if(b) {
      
   } else { // i have same amount of indents as my matching if, works!
     
   }
}

这不起作用:

if(a) {
    if(b) {
        } else { // i have to many indents.
           
        }
  
}

  • 同一行不能有ifelse! (应该不是通常..)

这是我想出的脚本,它存储所有行号 if 而没有 else。你可以检查行号并单击给定的 if,然后 vs 代码突出显示结束括号,你可以添加 else。它使用 lodash 但最终仅用于扁平化结果。这不是真正的依赖..

import { EOL } from 'os'
import * as fs from 'fs'
import { flatten } from 'lodash'

// Import your code file:
const code = fs.readFileSync('code.js').toString()

// Regex for matching lines holding if's..
// if(...)
// if() {
// if
const match_if = /if\s?\([^)]+\)\s+?/

// Regex for matching lines holding else:
// }else
// } else
// else {
// }else{
// ...
const match_else = /(\n|})\s?else({|\s|$)/


// small helper fpr calculating indents for first character appearing..
const calculate_indent = (line: string) => {
    let spaces = 0
    while(line.charAt(spaces) === ' ') {
        spaces++
    }
    return spaces
}

// split up the lines by system operator
const lines = code.split(EOL)
const indexes = []

// iterate all lines.
for(let i =0; i < lines.length; i++) {
    const line = lines[i]

    // do not process empty lines..
    if(!line || line.trim().length < 2) {
        continue
    }


    // Match the line against if regex
    const if_match = line.match(match_if)

    // process the match if there is an if found!
    if(if_match && if_match.length > 0) {

        // Count the indents, we need this latere
        // to match any found "else" to the correct if.
        // make sure your code is properly formatted and indent levels are correct!!
        const level = calculate_indent(line)


        // Make sure under given level is an array
        if(Array.isArray(indexes[level]) === false) {
            indexes[level] = []
        }

        // store line number to the given level. 
        // For a human the line number is index + 1
        indexes[level].push(i+1)
    }


    // We check the line for else. Note:
    // The whole function won't work for any if() else combinations on the same line..
    const else_match = line.match(match_else)
    if(else_match && else_match.length > 0) {
        
    
        // count index to identify level for matching the correct if.
        const level = calculate_indent(line)

        if(Array.isArray(indexes[level])) {
            // remove the last stored if. We know it ended here!
            indexes[level].splice(indexes[level].length-1, 1)
        } 

    }

}

console.log('lines:', lines.length)
console.log('results:', indexes)

// flatten / remove empty items / sort
const line_numbers = flatten(indexes).filter(d => !!d).sort((a,b) => a-b)

console.log('final lines:', line_numbers)

我用这段代码测试了它:

if(sdf) {

    if(sdf) {
            
    }
}



if(asdf) {

    if(sdfsdf) {


        if(sdfsdf) {

        } else {

        }
    } else {

    }
} else {
    
}


if(asdf) {

    if(sdfsdf) {

    } else {
        if(sdf) {

        }

        if(sdf) {
            
        } else {

        }


        if(sdf) {

        }
    }
}

结果 => final lines: [ 2, 4, 29, 34, 45 ] 在使用它之前,您可能想多测试一下! 但是当缩进正确时它应该可以工作。这篇文章也是相关的,很高兴阅读! => why you should not use regex to parse tree structures....