仅删除某些其他匹配行之间的空白行

时间:2017-08-29 17:32:49

标签: javascript regex

我正在尝试删除与特定模式匹配的其他行之间的空白行。就我而言,该模式只是该行以-字符开头。

const orig = `
- line1

- line2

- line3

- line4

- line5
`.trim();

const actual =
  orig.replace(/((?:^|\n)-.*\n)\n(-)/g, '$1$2');

在上面的代码中,我使用正则表达式进行匹配:

  • 换行符(或字符串开头),然后是......
  • -前缀行,后跟..
  • 一个空行,然后是......
  • 另一个-

我全局用两个省略它们之间空行的捕获组替换整个表达式。这种的工作方式与我预期的一样,但省略了其他所有空行,我不知道为什么。

我希望上面的代码能够给我这个:

- line1
- line2
- line3
- line4
- line5

......它实际上给了我这个:

- line1
- line2

- line3
- line4

- line5

Here is a fiddle that demonstrates the problem.

问题:正则表达式导致此行为怎么办?

奖励:有更好的方法吗? (例如通过split / reduce - 虽然我仍然想知道它为什么不起作用)

6 个答案:

答案 0 :(得分:2)

最后-是消费模式的一部分。 (-)匹配后,正则表达式索引会在-之后设置,但由于-中的(?:^|\n)--不匹配,您无法找到匹配项。你需要把它放在积极的前瞻中。然后,您需要使用m修饰符让^匹配位置的开头,而不仅仅是字符串的开头。

使用

/((?:^|\n)-.*\n)\n(?=-)/gm

请参阅regex demo。替换字符串减少到$1,因为只剩下一个捕获组。

这是固定表达式演示:

const orig = `
- line1

- line2

- line3

- line4

- line5
`.trim();

const actual =
	orig.replace(/((?:^|\n)-.*\n)\n(?=-)/gm, '$1');

document.getElementById('orig').innerText = orig;
document.getElementById('actual').innerText = actual;
ul { font-family: sans-serif; list-style: none; padding: 0; }
li { display: inline-block; padding: 1em; vertical-align: top; }
<ul>
  <li><h3>Original</h3><pre id="orig"></pre></li>
  <li><h3>Expected</h3><pre>- line1<br />- line2<br />- line3<br />- line4<br />- line5</pre></li>
  <li><h3>Actual</h3><pre id="actual"></pre></li>
</ul>

答案 1 :(得分:2)

此行为的原因是正则表达式不会重叠匹配。它消耗和匹配:

- line 1

- 

取代:

- line 1
- 

然后继续从上一场比赛结束时遍历字符串。

因此,它与下一个换行符不匹配,因为

  line 2

- line 3

不包含与您的模式匹配的内容。您的模式的下一个匹配将是

<newline>
- line 3

-

替换为:

<newline>
- line 3
-

解决此问题的方法是使用允许lookaheads or lookbehindsconditional matching based on surrounding patterns without consuming those patterns

我们可以稍微修改您的模式以使用前瞻以确保下一行符合模式

const actual = orig.replace(/^(-.*\n)\n(?=-)/gm, '$1');

https://regex101.com/r/fPUkYh/4

我还将((?:^|\n)-.*\n)\n更改为^(-.*\n)\n并添加了m标记,因为行断言^的开头不需要位于捕获组和{{ 1}}导致删除前面的换行符。

此模式也可以修改为匹配任意数量的bl;在与模式匹配的行之间的ank行:

\n

https://regex101.com/r/X7B7pi/2

答案 2 :(得分:1)

使用多行修饰符//m

时足够简单
 (                             # (1 start), Stuff to write back
      ^                             # BOL
      - .* 
      \r? \n      
 )                             # (1 end)
 \s*                           # Blank lines to remove
 \r? \n 

&#13;
&#13;
var orig_str = "- line1\n\n\n- line2\n\n- line3\n\n- line4\n\n- line5\n- line6";

var new_str =
	orig_str.replace(/(^-.*\r?\n)\s*\r?\n/mg, '$1');
  
  
console.log( "Original\n--------\n" +  orig_str + "\n" );
console.log( "New\n--------\n" +  new_str );
&#13;
&#13;
&#13;

输出

Original
--------
- line1


- line2

- line3

- line4

- line5
- line6


New
--------
- line1
- line2
- line3
- line4
- line5
- line6

如果恰好在-lines之间,只需在中添加断言即可 结束(^-.*\r?\n)\s*\r?\n(?=-)

答案 3 :(得分:0)

您可以通过以下方式执行此操作

const orig = `
- line1

- line2

- line3

- line4

- line5
`.trim();

const actual =
	orig.replace(/(\-[^\n]*)([^-]*)(?=-)/g, '$1\n');

document.getElementById('orig').innerText = orig;
document.getElementById('actual').innerText = actual;
<ul>
  <li><h3>Original</h3><pre id="orig"></pre></li>
  <li><h3>Expected</h3><pre>- line1<br />- line2<br />- line3<br />- line4<br />- line5</pre></li>
  <li><h3>Actual</h3><pre id="actual"></pre></li>
</ul>

请参阅regex demo

答案 4 :(得分:0)

这里是一个较短的正则表达式,包括你的模式:

const actual = orig.replace(/(-.*\n)\n/g, '$1');

答案 5 :(得分:-1)

这将为您提供所需 -

const actual = orig.replace(/\n\n|\r\r/g, "\n");