我正在尝试删除与特定模式匹配的其他行之间的空白行。就我而言,该模式只是该行以-
字符开头。
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
- 虽然我仍然想知道它为什么不起作用)
答案 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 lookbehinds的conditional 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
答案 2 :(得分:1)
使用多行修饰符//m
( # (1 start), Stuff to write back
^ # BOL
- .*
\r? \n
) # (1 end)
\s* # Blank lines to remove
\r? \n
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;
输出
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");