grep 正则表达式仅在一行不以以下开头时才匹配

grep regex match only if a line doesn't start by

i put a test file at the bottom of this post with a expected result

我想要什么


我在文件夹中有一些文件,例如:

src
├── app
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── interceptor
│       └── json-api.interceptor.ts
├── auth
│   ├── auth.controller.ts
│   ├── auth.module.ts
│   ├── auth.service.ts
│   ├── decorator
│   │   ├── auth-user.decorator.ts
│   │   ├── is-secret.decorator.ts

我想要一个脚本来检索我的 jsdoc 到这个文件中加上 jsdoc 相关函数的名称,并将结果插入到 .md 文件中。

jsdoc 始终以 /** 换行开始,并始终以 */ 换行结束。

起点和终点之间的线总是以 * 开始。

在 jsdoc 的最后一行之后我们有 @[A-Za-z]。仅当模式不等于 @.

时,我才想匹配此行

示例:

/** << start
 *  << the line between
 */ << end
@ xxxxxx << possible negative value
function xxxxx << possible positive value
const xxxx << possible positive value
xxxxx << possible positive value

但我不想检索以下模式:

/** something */
@ or xxxxxx

我的研究


我从 jsdoc 开始:

grep -Pro "(\/\*\*$)|(^\s+\*\s.*)|(^\s+\*\/$)" test.txt

结果还可以:

➜ grep -Pro "(\/\*\*$)|(^\s+\*\s.*)|(^\s+\*\/$)" test.txt
/**
   * check if the user level is super admin
   * @returns {boolean} true if the user has the right to access super admin endpoints
   */
/**
   * check if the user level is super admin
   * @returns {boolean} true if the user has the right to access super admin endpoints
   */
/**
   * check if the user level is super admin
   * @returns {boolean} true if the user has the right to access super admin endpoints
   */

现在,如果此行不是以 @ 开头,我想在后面添加一行,为此我制作了这个正则表达式

((\s*)([^@]|\w)(.*))

但这根本行不通。

如果我使用否定前瞻 (\s*)(?![@])(.+) 控制台会告诉我 event not found: [@])(.+)

我很迷茫,如果你知道怎么做,谢谢。如果您想了解更多信息,请告诉我。

测试文件和预期结果


➜ cat test.txt 
// case 1
  /**
   * check if the user level is super admin
   * @returns {boolean} true if the user has the right to access super admin endpoints
   */
  @UseGuards(AuthGuard('jwt'), LevelsGuard)
  @Levels(LevelEnum.superadmin)
  @Get('check/superadmin')
  @ApiBearerAuth()
  checkSuperAdminLevel(): boolean {
    return true;
  }

// case 2
  /**
   * check if the user level is super admin
   * @returns {boolean} true if the user has the right to access super admin endpoints
   */
  @Get('check/superadmin')
  @ApiBearerAuth()
  checkSuperAdminLevel(): boolean {
    return true;
  }

// case 3
  /**
   * check if the user level is super admin
   * @returns {boolean} true if the user has the right to access super admin endpoints
   */
  checkSuperAdminLevel(): boolean {
    return true;
  }

// case 4
  /** lorem ipsum */

// case 5
  lorem ipsum

预期结果

// case 1
/**
 * check if the user level is super admin
 * @returns {boolean} true if the user has the right to access super admin endpoints
 */
checkSuperAdminLevel(): boolean {

// case 2
/**
 * check if the user level is super admin
 * @returns {boolean} true if the user has the right to access super admin endpoints
 */
checkSuperAdminLevel(): boolean {

// case 3
/**
 * check if the user level is super admin
 * @returns {boolean} true if the user has the right to access super admin endpoints
 */
checkSuperAdminLevel(): boolean {

// case 4
nothing

// case 5
nothing

由于您使用的是 GNU grep,因此可以进一步扩展您的正则表达式来实现您想要的效果。

首先,添加 -z 选项,它将允许将文件插入单个字符串输入(grep 模式将“看到”换行符)。

其次,您需要确保 $ 锚点匹配 的末尾,而不仅仅是整个字符串,因此您需要 多行修饰符,(?m).

第三,换行符也需要匹配,以便在输出中有换行符,因此,在每个选项的末尾,您需要放置 \n?,一个可选的换行符。

第四,由于这是一个 PCRE 模式,它将支持 \h 构造,匹配任何水平空格。当您的正则表达式可以跨行匹配时,这是一个方便的模式。注意 \s 匹配换行符,这可能会导致不受欢迎的匹配。因此,所有 \s 都替换为 \h

第五,由于该模式将消耗 */ 行,并且您想开始寻找不以 @ 开头的行,仅在该行正下方,您需要一个 positive lookbehind,一种非消耗模式。

所以,grep 命令看起来像

grep -zroP '(?m)/\*\*$\n?|^\h+\*\h.*$\n?|^\h+\*/$\n?|(?<=\*/\n)(?:\h+@.*\n)*\K.+\n?' test.txt

(?<=\*/\n)(?:\h+@.*\n)*\K.+\n? 替代方案是这样做的:

  • (?<=\*/\n) - 查找紧跟在 */ 和换行符
  • 之前的位置
  • (?:\h+@.*\n)* - 匹配并消耗任何零次或多次重复
    • \h+ - 一个或多个水平空格
    • @ - 一个 @ 字符
    • .*\n - 带有换行符 (LF) char
    • 的行的其余部分
  • \K - 匹配重置运算符,丢弃到目前为止匹配的文本从整体匹配内存缓冲区
  • .+ - 非空行
  • \n? - 一个可选的 LF(换行符)字符。

参见regex demo