【问题标题】:Match and replace every 7th instance of a <td> tag匹配并替换 <td> 标记的每 7 个实例
【发布时间】:2021-02-23 00:30:52
【问题描述】:

我正在努力思考如何让这个正则表达式在 Visual Studio Code 中工作。

我正在尝试匹配 &lt;td&gt; 标记的每 7 个实例,然后将其替换为 &lt;td data-order=""&gt;

原创

<tr>
<td>1</td>
<td>Name</td>
<td>Owner</td>
<td>Value</td>
<td>Total</td>
<td>Percent</td>
<td>Ratio</td>
<td>Final</td>
</tr>

我想要什么

<tr>
<td>1</td>
<td>Name</td>
<td>Owner</td>
<td>Value</td>
<td>Total</td>
<td>Percent</td>
<td data-order="">Ratio</td>
<td>Final</td>
</tr>

我尝试了((?:.*&lt;td&gt;){1}) 的变体,但任何大于 1 的数字只会给我一个“无结果”消息。

【问题讨论】:

  • 这不清楚:第 7 个 &lt;td&gt; 是否应该在同一个 &lt;tr&gt; 和表内? ((?:.*&lt;td&gt;){1}) 应该匹配什么?这显然不匹配任何第七个td

标签: html regex visual-studio visual-studio-code


【解决方案1】:

[您说“每 7 个实例匹配一次”,但我认为您的意思是匹配第 7 个实例,而不是第 7 个、第 14 个、第 21 个等。假设您的意思是仅第 7 个......”]

如果您的数据确实像您展示的那样规则且结构化,您可以将其用作 Find

中的正则表达式

查找:(?&lt;=&lt;tr&gt;\n(?:&lt;td&gt;.*&lt;\/td&gt;\n){6})(&lt;td)
替换:&lt;td data-order=""

如果&lt;td&gt;...\n...&lt;/td&gt; 标记中可能有换行符,请使用此

查找:(?&lt;=&lt;tr&gt;\n(?:&lt;td&gt;[^/]*&lt;\/td&gt;\n){6})(&lt;td)
替换:&lt;td data-order=""

Vscode 的查找/替换(在一个文件中)可以使用非固定长度的lookbehind like

(?&lt;=&lt;tr&gt;\n(?:&lt;td&gt;.*&lt;\/td&gt;\n){6})

跨文件搜索无法做到这一点,所以这个正则表达式在那里不起作用。像 regex101.com 这样的网站也不能使用它,所以我将在 vscode 中展示一个演示:

【讨论】:

  • 这就是答案,谢谢马克。我一直在 regex101.com 上玩,并意识到它的功能与 VS Code 不同。你的 GIF 也很有帮助。
【解决方案2】:

您可以使用扩展名Select By。并使用命令moveby.regex

在您的keybindings.json 中定义一个键绑定以搜索下一个&lt;td&gt; 标记。

  {
    "key": "ctrl+i ctrl+u",  // or any other key combo
    "when": "editorTextFocus",
    "command": "moveby.regex",
    "args": {
      "regex": "<td[^>]*>",
      "properties": ["next", "end"]
    }
  }
  1. 选择您要开始的第一个&lt;tr&gt;标签
  2. 选择以下每个&lt;tr&gt; 标记:
    • 命令:将选择添加到下一个查找匹配项
      (Ctrl+D - editor.action.addSelectionToNextFindMatch)
    • 菜单选项:选择 > 选择所有事件
  3. 根据需要多次应用键绑定
  4. 您的光标现在位于第 n 个 &lt;td&gt; 标记之后
  5. 进行任何您想要的编辑
  6. Esc 退出多光标模式

Select By v1.2.0 中,您可以指定重复计数。计数可以固定或向用户询问。

  {
    "key": "ctrl+i ctrl+u",  // or any other key combo
    "when": "editorTextFocus",
    "command": "moveby.regex",
    "args": {
      "regex": "<td[^>]*>",
      "properties": ["next", "end"],
      "repeat": "ask"
    }
  }

如果您省略了属性 "regex",系统也会要求您输入正则表达式。

编辑

使用正则表达式需要相当长的时间才能使其正确

let testStr =`<tr>
<td>1</td>
<td>Name</td>
<td>Owner</td>
<td>Value</td>
<td>Total</td>
<td>Percent</td>
<td>Ratio</td>
<td>Final</td>
</tr>`;

var replace = '$1<td class="red">$2';
var regex = new RegExp("(<tr>[\n\r\s]*(?:<td[^>]*>(?:.|[\n\r\s])*?</td>[\n\r\s]*){6})<td>((?:.|[\n\r\s])*</tr>)");
var newstr=testStr.replace(regex,replace);
console.log(newstr);

document.getElementById("test").innerHTML=newstr
.red {
  color: red
}
<table>
  <tbody  >
  <tr id="test">
  </tr>
  </tbody>
</table>

【讨论】:

  • 哇,那个正则表达式...我为什么还要尝试:(
  • @ikiK 可能的换行符使它更复杂,一些正则表达式引擎解释捕获组不同,可能是 VSC 做的有点不同,你可以使用[\r\n\s\S],但 SO 需要它有点不同
【解决方案3】:

我对此很感兴趣,因为我不太了解正则表达式并且需要学习,但我设法分两次完成。

我希望有人能纠正我并帮助纠正一种方式。

我试图遵循这个:但无法让它工作:Find Nth Occurrence of Character

let testStr = '<td>1</td><td>Name</td><td>Owner</td><td>Value</td><td>Total</td><td>Percent</td><td>Ratio</td><td>Final</td>';

var replace = '<td class="red">';
var regex = new RegExp("((<td>.*?)){7}");
// tried with a lot of (?:...) combinations here but none works :(
var newstr=testStr.replace(regex,replace);

var regex2 = new RegExp("((</td>.*?)){6}");
var newstr2=testStr.match(regex2);

console.log(newstr);
console.log(newstr2[0]);

document.getElementById("test").innerHTML=newstr2[0]+newstr
.red {
  color: red
}
<table>
  <tbody  >
  <tr id="test">
  </tr>
  </tbody>
</table>

编辑: 得到了一些东西:)

let testStr = '<td>1</td><td>Name</td><td>Owner</td><td>Value</td><td>Total</td><td>Percent</td><td>Ratio</td><td>Final</td>';

var replace = '<td class="red">';
var regex = new RegExp("(?:[</td>]){6}(<td>)");
var newstr=testStr.replace(regex,replace);

console.log(newstr);

document.getElementById("test").innerHTML=newstr
.red {
  color: red
}
<table>
  <tbody  >
  <tr id="test">
  </tr>
  </tbody>
</table>

@rioV8的帮助下:

let testStr = '<td>1</td><td>Name</td><td>Owner</td><td>Value</td><td>Total</td><td>Percent</td><td>Ratio</td><td>Final</td>';

var replace = '$1<td class="red">';
var regex = new RegExp("((?:.*?</td>){6})<td>");
var newstr=testStr.replace(regex,replace);

console.log(newstr);

document.getElementById("test").innerHTML=newstr
.red {
  color: red
}
<table>
  <tbody  >
  <tr id="test">
  </tr>
  </tbody>
</table>

【讨论】:

  • 如果表格有 20 列,这将失败,并且您必须考虑到&lt;td&gt; 标签之间可能有换行符
  • @rioV8 就像我提到的,我不知道我在做什么 ;) 但是,20 列之后怎么会失败?这两个 RegExp 的计数从一开始?并且可以忽略新行?
  • OP 询问 每个 7th td 标签,对于表格的所有行,您不会从 tr 标签开始,所以 td 标签 14行也将被更改,对于所有行,您必须执行 global 搜索替换
  • .*?有什么用,后面什么都没有所以会匹配0个字符,组的默认重复是{1}所以也是多余的
  • @rioV8 是的,我注意到了,但是你能解释一下Percent 中的最后一个t 是怎么丢失的吗?它让我发疯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-13
  • 2016-10-20
  • 1970-01-01
  • 2015-08-30
  • 2018-01-02
  • 1970-01-01
  • 2016-07-22
相关资源
最近更新 更多