【问题标题】:Cleaning Strings dynamically动态清理字符串
【发布时间】:2022-01-06 03:39:07
【问题描述】:

我在学习 puppeteer 时正在抓取网页作为一个有趣的小项目,在那段时间里,我在清理字符串以获取 有用 数据时遇到了一些问题.我想出了一些从他们那里提取我想要的数据的简单方法,但是我遇到了一些我不知道处理事情的最佳方法的极端情况。

取这个字符串

Round 1 - Foo Bar (SchoolName) over John (JC) Cena (Fake School Name) (Fall 1:19)

我想得到的数据。

  • 获奖者姓名 = Foo Bar
  • 获胜者的学校 =(学校名称)
  • 失败者的名字 = 约翰·塞纳
  • 失败者的学校 = 假学校名称

Round 1- 对我来说毫无用处,它们在整个应用程序中遵循相同的结构。所以,使用只选择这些项目应该在的索引的方法,应该很容易。

此字符串中最重要的索引是over 所在的位置。一旦我找到了,我就可以搜索它周围的索引来找到我需要的其余信息在哪里。

let findOver = arr.indexOf('over')
let winnerName = arr[over - 3].concat(' ', arr[over - 2])
let winnerSchool = summaryBreakUp[over - 1]

这适用于上面的字符串,至少适用于左侧。它会获取获胜者的名字和姓氏并将他们连接起来。

我的问题是,当字符串看起来不像左侧时,如何考虑上述边缘情况。

我可以搜索所有( && ) 并捕获其中的所有数据以获得School Names,但是我需要筛选一种方法来确定哪个是学校,哪个是昵称。

任何方向将不胜感激。我还会发布更多示例,以防其他人想尝试一下。

这是对未指定对手的胜利。
Michael Macontish (Fairview) over Unknown (For.)
没有给出回合
John Heflin (Arlington) over Random Kid (Mistview) (Fall 1:59)
没有跌倒
Round 2 - Logan Paul George (High School) over Dontae Inverse (Jackson County) (Dec 3-0)

【问题讨论】:

  • 这就是正则表达式的用途。您现在有 2 个问题!
  • 正则表达式如何解决我的问题?

标签: javascript reactjs string split concatenation


【解决方案1】:

作为替代模式,您可以扩大匹配范围,使用非贪心点 .*? 匹配任何字符或否定字符类 [^ 以排除允许匹配的内容。

选择匹配以 - 开头的部分来启动模式。

要匹配末尾括号之间的正确部分,您可以断言括号之间的部分没有 - 或 : 使用负前瞻的数字之间。

(?:.*?\s+-\s+)?([^()]+)\s+\(([^()]+)\)\s+over\s+(.*)\s+\((?![^()]*\d[-:]\d[^()]*\))([^()]*)\)

模式匹配:

  • (?:.*?\s+-\s+)? 可选匹配以<code> - </code> 结尾的部分
  • ([^()]+) 捕获 group 1 以匹配除 () 之外的任何字符
  • \s+ 匹配 1+ 个空格字符
  • \(([^()]+)\) 匹配 ( 然后在 group 2 中捕获除 () 之外的任何字符并匹配 )
  • \s+over\s+Matchover` 在 1 个或多个空白字符之间
  • (.*) 捕获 group 3 中的任何字符
  • \s+ 匹配 1+ 个空格字符
  • \(匹配(
  • (?![^()]*\d[-:]\d[^()]*\)) 负前瞻,断言括号之间没有:- 数字之间
  • ([^()]*) 如果断言为真,则在 组 4 中捕获除 () 之外的任何字符
  • \)匹配)

查看regex demo

const regex = /(?:.*?\s+-\s+)?([^()]+)\s+\(([^()]+)\)\s+over\s+(.*)\s+\((?![^()]*\d[-:]\d[^()]*\))([^()\n]*)\)/;
[
  "Round 1 - Foo Bar (SchoolName) over John (JC) Cena (Fake School Name) (Fall 1:19)",
  "Michael Macontish (Fairview) over Unknown (For.)",
  "John Heflin (Arlington) over Random Kid (Mistview) (Fall 1:59)",
  "Round 2 - Logan Paul George (High School) over Dontae Inverse (Jackson County) (Dec 3-0)"
].forEach(s => console.log(s.match(regex)));

【讨论】:

    【解决方案2】:

    使用正则表达式和捕获组来获取您感兴趣的位,您可能需要做一些小的整理。

    您可以使用许多模式(我确信这不是最好的,但这是一个开始):

    ([\w\s\(\)]+)\s\(([\s\w\.]+)\)\sover\s([\w\s\(\)]+)\s\(([\s\w\.]+)\)
    

    这与名称匹配

    • 任何字母数字、下划线、空格或括号
    • 一次或多次发生

    后跟一个左括号,后跟学校为

    • 任何空格、字母数字、下划线或句点
    • 一次或多次发生

    后跟一个右括号,然后是空格,然后是单词“over”,再次空格,然后重复名称和学校模式。其他所有内容都被忽略。


    用法:当您在 javascript 中使用正则表达式时,捕获组最终会成为结果数组中的元素。整个匹配是第一个元素,每个附加元素按顺序表示捕获组。此表达式中有 4 个捕获组,因此您最终会得到代表 name1、school1、name2 和 school2 的元素 1-5。

    const re = /([\w\s\(\)]+)\s\(([\s\w\.]+)\)\sover\s([\w\s\(\)]+)\s\(([\s\w\.]+)\)/
    
    const input = [
      'Round 1 - Foo Bar (SchoolName) over John (JC) Cena (Fake School Name) (Fall 1:19)',
    'Michael Macontish (Fairview) over Unknown (For.)',
    'John Heflin (Arlington) over Random Kid (Mistview) (Fall 1:59)',
    'Round 2 - Logan Paul George (High School) over Dontae Inverse (Jackson County) (Dec 3-0)'
    ]
    
    
    input.forEach( i => {
       console.log(i.match(re))
    })

    【讨论】:

    • 非常优雅的答案。这可以按预期工作,尽管在处理名称中的 . 时我不得不对其进行一些修改。在进行更多测试后,我将更新正则表达式。
    猜你喜欢
    • 2016-11-29
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    • 2017-05-31
    • 2023-03-16
    相关资源
    最近更新 更多