1

这与如何在每 n 个字符或最近的前一个空格处拆分字符串类似的问题,但是,与我基于标题所期望的相反,如果只有一个没有任何空格的长单词,该解决方案将不起作用.

所以我需要一个正则表达式,它将一个字符串拆分为每行最大字符数(如果需要,可以多次),并向后看n 个字符以查找可能的空格(如果找到则中断,否则为最大长度)?

编辑 1:例如,最大行长 30 个字符和 15 个字符的向后空格查找:

Loremipsumissimplydummytextoftheprinting and typeing 行业。

该句子的第一个单词长度为 32 个字符。所以输出应该是:

Loremipsumissimplydummytextoft  # Line has length of 30 char
he printing and typesetting     # Cut before the word at otherwise 30 char
industry.

所以第一个单词应该在第 30 个字符之后被强制剪切,因为没有空格。

剩余的字符串在单词“industry”之前的长度为 28(或短划线为 29),因此在第 30 个字符的位置有一个单词,因此该解决方案在 15 个字符范围内查找前一个空格。那条线在“行业”一词之前被打破。

编辑 2:文本的第二个示例:

Loremipsumissimplydummytextoftheprinting and typeing 行业。Loremipsumis 只是印刷和排版行业的虚拟文本。Loremipsumissimplydummytextoftheprinting and typeing 行业。Loremipsumis 只是印刷和排版行业的虚拟文本。

应该输出:

Loremipsumissimplydummytextoft
he printing and typesetting
industry. Loremipsumis simply
dummytext ofthe printing and
typesetting industry.
Loremipsumissimplydummytextoft
he printing and typesetting
industry. Loremipsumis simply
dummytext ofthe printing and
typesetting industry.

此正则表达式的用例是将长字符串格式化为可读文本,强制执行最大行长度,并且行以字符而不是空格开头。

可选要求:在最初发布后,我在编辑 1 中添加了该示例时,我还添加了一个可选要求,即在下一行的开头添加一个破折号“-”字符,如果一个单词以最大行长度被剪切。我现在将其从示例中删除,并将其作为单独的可选要求添加到此处。

所以一个可选的要求:如果一行在最大长度而不是空格处被中断,那么应该在该行的末尾附加一个破折号(而不是在下一行的开头,正如我最初描述的那样)。

Loremipsumissimplydummytextoft-  # Line length 30+1 char with an appended a dash
he printing and typesetting     # Cut before the word at otherwise 30 char
industry.
4

2 回答 2

5

您可以使用

var s = "Loremipsumissimplydummytextofthe printing and typesetting industry. Loremipsumis simply dummytext ofthe printing and typesetting industry. Loremipsumissimplydummytextofthe printing and typesetting industry. Loremipsumis simply dummytext ofthe printing and typesetting industry.";
var regex = /\s*(?:(\S{30})|([\s\S]{1,30})(?!\S))/g;
console.log(
  s.replace(regex, function($0,$1,$2) { return $1 ? $1 + "-\n" : $2 + "\n"; } )
)

细节

  • \s*- 0 个或更多空白字符。
  • (?:- 非捕获组的开始:
    • (\S{30})- 第 1 组(与$1回调方法中的变量一起引用):三十 ( n) 个非空白字符
    • |- 或者
    • ([\s\S]{1,30})(?!\S))- 第 2 组(与$2回调方法中的变量一起引用):任意 1 到 30 ( n) 个字符,尽可能多,但不要紧跟非空白字符。

function($0,$1,$2) { return $1 ? $1 + "-\n" : $2 + "\n"; }部分表示如果 Group 1 匹配(即,我们匹配了一个很长的单词被分成两部分),我们将匹配替换为 Group 1 值 + 连字符和换行符。否则,如果第 2 组匹配,我们将替换为第 2 组值 + 换行符。

符合 ES6+ 的代码片段

const text = "Loremipsumissimplydummytextofthe printing and typesetting industry. Loremipsumis simply dummytext ofthe printing and typesetting industry. Loremipsumissimplydummytextofthe printing and typesetting industry. Loremipsumis simply dummytext ofthe printing and typesetting industry.";
const lineMaxLen = 30;
const wsLookup = 15; // Look backwards n characters for a whitespace
const regex = new RegExp(String.raw`\s*(?:(\S{${lineMaxLen}})|([\s\S]{${lineMaxLen - wsLookup},${lineMaxLen}})(?!\S))`, 'g');
console.log(
  text.replace(regex, (_, x, y) => x ? `${x}-\n` : `${y}\n`)
);

于 2020-02-17T15:30:16.403 回答
1

最终答案:

(\S[\s\S]{1,30}$|\S[\s\S]{1,29}(?:\s+)|\S{30})

进化:

  1. ([\s\S]{1,15}(?!\S)|\S{15,})

您只需通过添加附加要求的“或”语句修改链接中的答案:|\S{15,}

  1. 回应您的编辑,这是我修改后的正则表达式: ([\s\S]{1,15}(?!\S)|\S{15})

您可以将 15s 替换为 30 或您选择的字符截止

  1. 调整您的进一步澄清: (\S[\s\S]{1,14}(?:\s*)|\S{15})

现在字符串必须以非空格开头,它匹配但不捕获前 15 个字符之后的额外空格。同样,您需要将 15 和 14 更改为您想要的长度。

  1. (\S[\s\S]{1,30}$|\S[\s\S]{1,29}(?:\s+)|\S{30}) 在多个 'or 中添加另一个条件' 开头的语句,如果字符串以非空白字符结尾,则捕获字符串的结尾。如果它以空格字符结尾,则“或”语句的第二部分将捕获它。
于 2020-02-17T12:50:39.877 回答