【问题标题】:Javascript Regex capture multiline content from each newline entryJavascript Regex 从每个换行条目中捕获多行内容
【发布时间】:2016-01-31 12:36:12
【问题描述】:

我正在使用 Javascript Regex 来处理一些原始数据并将其转换为二维数组。

任务简报(仅限 JS):

将原始字符串数据转换为二维数组。

原始数据输入:

这是一个包含 4 个条目的示例,新条目将转到换行符。条目 3 带有多行内容。

2012/12/1,上午 12:21 - 用户 1:entry1_wasehhjdsaj

2012/12/2,AM9:42 - 用户 2:entry2_bahbahbah_dsdeead

2012/12/2,AM9:44 - 用户 3:entry3_Line1_ContdWithFollowingLine_bahbahbah

entry3_Line2_ContdWithABoveLine_bahbahbah_erererw

entry3_Line3_ContdWithABoveLine_bahbahbah_dsff

2012/12/4,AM11:48 - 用户 7:entry4_bahbahbah_fggf

(原始字符串数据,没有空行。) 更新:抱歉误导,内容的结尾不一定有相同的 END 模式,而只是一个换行符。

模式实际上是如何结束的?(感谢@Tim Pietzcker 的评论)。 内容应该以换行符结束,然后是下一个条目时间戳开始。 (您可以假设条目内容不包含任何类似的时间戳模式。)

我知道这可能是一个麻烦的正则表达式问题,因此任何其他实现相同目标的 JS 方法也将被接受。

我当前的正则表达式与捕获组:

/^([0-9]{4}|[0-9]{2})[\/]([0]?[1-9]|[1][0-2])[\/]([0]?[1-9]|[1|2][0-9]|[3][0|1]), ([A|P])M([1-9]|1[0-2]):([0-5]\d) - (.*?): (.*)/gm

想要的捕获结果:

第一场比赛

  1. 2012
  2. 12
  3. 1
  4. A
  5. 12
  6. 21
  7. user1‬
  8. entry1_wasehhjdsaj

第 2 场

  1. 2012
  2. 12
  3. 2
  4. A
  5. 9
  6. 42
  7. user2‬
  8. entry2_bahbahbah_dsdeead

第 3 场比赛

  1. 2012
  2. 12
  3. 2
  4. A
  5. 9
  6. 44
  7. user3‬
  8. entry3_Line1_ContdWithFollowingLine_bahbahbah entry3_Line2_ContdWithABoveLine_bahbahbah_erererw entry3_Line3_ContdWithABoveLine_bahbahbah_dsff

第 4 场比赛

(被跳过...)


问题:

捕获Entry 3时出现问题,无法捕获Entry 3的第2行和第3行内容。如果该entry仅包含一行内容,则正则表达式可以正常工作。

如何捕获条目 3 的多行内容? 我尝试使用 m 修饰符,但我不知道如何同时处理多行内容和换行条目.

如果用js正则无法实现,请建议另一种js方法将原始数据转换为二维数组作为最终目标。

谢谢!

内容的结尾不一定要有相同的 END 模式,而只是一个换行符。

测试:https://regex101.com/r/eS9pY5/1

【问题讨论】:

    标签: javascript regex multiline capturing-group


    【解决方案1】:

    多行在 javascript 中不能以这种方式工作,但您可以使用 [\s\S] 解决它。这个类也匹配每个字符和 \n。注意 *? 而不是 * 在它之后,以防止它变得贪婪并且只到第一个 END

    ^([0-9]{4}|[0-9]{2})[\/]([0]?[1-9]|[1][0-2])[\/]([0]?[1-9]|[1|2][0-9]|[3][0|1]), ([A|P])M([1-9]|1[0-2]):([0-5]\d) - (.*?): ([\s\S]*?END)$
    

    见:https://regex101.com/r/mT8rI4/3

    【讨论】:

    • 更新:抱歉误导,内容的结尾不一定有相同的 END 模式,而只是一个换行符。
    【解决方案2】:

    点 (.) 与换行符不匹配。有一个匹配所有内容的字符类 ([\S\s]),但你不想在没有预防措施的情况下使用它 - 否则 [\S\s]* 会同时匹配所有条目。

    所以你需要告诉正则表达式引擎在下一个匹配开始时停止匹配。我们可以为此使用negative lookahead assertion,我们只需将时间戳模式输入其中:

    /^([0-9]{4}|[0-9]{2})\/(0?[1-9]|1[0-2])\/(0?[1-9]|[12][0-9]|3[01]), ([AP])M([1-9]|1[0-2]):([0-5]\d) - ([^:]*): ((?:(?!^([0-9]{4}|[0-9]{2})\/(0?[1-9]|1[0-2])\/(0?[1-9]|[12][0-9]|3[01]), ([AP])M([1-9]|1[0-2]):([0-5]\d))[\S\s])*)/gm
    

    测试它live on regex101.com

    【讨论】:

    • javascript 正则表达式没有 s 标志
    • @jcubic:是的,这是一个复制/粘贴事故。
    • 更新:抱歉误导,内容的结尾不一定有相同的 END 模式,而只是一个换行符。
    • @cint:如果是这样,你怎么知道模式何时真正结束?
    • 好问题!内容应该以换行符结束,并在下一个条目时间戳开始之后。 (您可以假设条目内容不包含任何相同的时间戳模式)。我知道这可能是一个麻烦的正则表达式问题,所以任何其他 JS 方法也将被接受。
    【解决方案3】:

    这是一个单一的正则表达式,可以按照您需要的方式匹配字符串:

    ^(\d{4}|\d{2})\/(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01]), ([AP])M([1-9]|1[0-2]):([0-5]\d) - (.*?): ((?:(?!(?:\d{4}|\d{2})\/(?:0?[1-9]|1[0-2])\/(?:0?[1-9]|[12]\d|3[01]))[\s\S])*)(?=\n|$)
    

    demo

    最后一个捕获组不再是匹配 .* 的贪婪点,而是匹配到字符串末尾或日期模式的所有内容的经过调整的贪婪令牌 (?:(?!([0-9]{4}|[0-9]{2})\/(0?[1-9]|1[0-2])\/(0?[1-9]|[12][0-9]|3[01]))[\s\S])*

    如果我们展开它以提高效率:

    ^(\d{4}|\d{2})\/(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01]), ([AP])M([1-9]|1[0-2]):([0-5]\d) - (.*?): (\D*(?:\d(?!(?:\d{3}|\d)\/(?:0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01]))\D*)*)(?=\n|$)
    

    another demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-10
      • 2019-04-17
      • 2011-12-21
      • 2015-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多