【问题标题】:Partial String Match - Dynamic Strings部分字符串匹配 - 动态字符串
【发布时间】:2021-05-09 01:42:28
【问题描述】:

对于某些动态字符串,例如:

  • 截至 2021 年 5 月 5 日的 covid-19 测试状态
  • 截至 2021 年 5 月 4 日的 covid-19 测试状态
  • 截至 2021 年 5 月 1 日的 covid-19 测试状态
  • ....
  • 截至 {{date}} 的 covid-19 测试状态

还有其他类似的:

  • 杰克和琼斯是朋友
  • Jack 和 JC 是朋友
  • 杰克和伊拉尼是朋友
  • .....
  • Jack 和 {{friend-name}} 是朋友

我想匹配传入的字符串,如:

covid-19 testing status upto may 01,2021

与

covid-19 testing status upto {{date}}

如果有匹配,我想提取date的值。

类似地,对于像这样的传入字符串

Jack and JC are friends

我想匹配

Jack and {{friend-name}} are friends

并提取JC 或朋友姓名。我怎么能这样做?

我正在尝试创建一个设置,其中可以将这些动态字符串合并为一个。可能有数以千计的传入字符串要与现有模式进行匹配。

INCOMING_STRINGS -------EXISTING-PATTERNS-----> 
   [
    covid-19 testing status upto {{date}}, 
    Jack and {{friend-name}} are friends, 
    ....
   ] ---> FIND THE PATTERN AND EXTRACT THE DYNAMIC VALUE

编辑

不保证模式将始终存在于传入的字符串中。

【问题讨论】:

  • 您可以为每个模式定义一个正则表达式并检查它们是否匹配。
  • @MrSmith42 你能帮忙回答我在问题中发布的 2 个示例字符串吗?这会有所帮助。
  • 这取决于,如果Jack and {name}...或covid-19 testing... {date}总是存在,那么使用for循环就足够公平了,否则你将无法准确提取日期或名称,你可以定义一个简单的相似度函数(例如,名称通常以大写字母开头),(日期通常由数字和特定分隔符组成)。
  • 如果模式很复杂或不存在模式,那么您需要为您的目标训练一个 AI 模型(自然语言模型),如果您只想匹配字符串,那么 cosine-similarity 会没事。
  • @4.Pi.n 可能有数百万个传入字符串,我需要从这些字符串中匹配现有模式。

标签: javascript string algorithm optimization


【解决方案1】:

在您的第二个示例中使用正则表达式非常容易。如果您对“朋友姓名”部分使用捕获组,则可以轻松提取:

const re = /Jack and ([a-zA-Z]+) are friends/
const inputs = ["Jack and Jones are friends",
"Jack and JC are friends",
"Jack and Irani are friends",
"Bob and John are friends"] // last one wont match

for(let i=0;i<inputs.length;i++){
  const match = inputs[i].match(re);
  if(match)
    console.log("friend=",match[1]);
  else
    console.log("No match for the string:", inputs[i])
}

第一个例子稍微难一些,但这只是因为正则表达式更难写。假设格式始终为“短月份名称 2 位数日逗号 4 位数年份”是可行的

const re = /covid-19 testing status upto ((jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (0?[1-9]|[12][0-9]|3[01]),\d{4})/
const inputs = ["covid-19 testing status upto may 05,2021",
"covid-19 testing status upto may 04,2021",
"covid-19 testing status upto may 01,2021",
"covid-19 testing status upto 01/01/2020"] // wrong date format

for(let i=0;i<inputs.length;i++){
  const match = inputs[i].match(re);
  if(match)
    console.log("date=",match[1]);
  else
    console.log("No match for the string:", inputs[i])
}

【讨论】:

  • 这是否意味着为检测到的每个模式创建一个新的正则表达式?
  • @Amanda 是的。您是否期望只写covid-19 testing status upto {{date}} 并且计算机神奇地知道{{date}} 的含义?
  • 当然不是! :) 如果这有助于我尝试创建一个与此处描述的流程非常相似的系统youtu.be/B34gHahWX_s 它会准确地说明我正在尝试做什么。
  • @Amanda 那么你想做什么?我怀疑系统使用的是NLP 而不是正则表达式。
  • 我们可以在这里讨论这个chat.stackoverflow.com/rooms/232070/…
【解决方案2】:

我不清楚您的实际输入和输出应该是什么。这是一个猜测。像

这样的输入
[{
  sample: 'covid-19 testing status upto may 05,2021',
  extract: 'may 05,2021',
  propName: 'date'
}, {
  sample: 'Jack and Jones are friends',
  extract: 'Jones',
  propName: 'friend-name'
}]

我们生成一个可以这样使用的函数:

mySubs ('Jack and William are friends')
//=> {"friend-name": "William"}

或

(mySubs ('covid-19 testing status upto apr 30,2021')
//=> {"date": "apr 30,2021"}

或

mySubs ('Jack and Jessica are friends who dicsussed covid-19 testing status upto apr 27,2021')
//=> {"date": "apr 27,2021", "friend-name": "Jessica"}

如果没有匹配项,则会产生一个空对象。

我们通过为我们的样本动态生成正则表达式来做到这一点,这些表达式将捕获所做的替换:

const regEscape = (s) =>
  s .replace (/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');


const makeTester = ({sample, extract, propName}) => ({
  regex: new RegExp (
    regEscape (sample .slice (0, sample .indexOf (extract))) + 
    '(.+)' + 
    regEscape (sample .slice (sample .indexOf (extract) + extract .length))
  ), 
  propName
})

const substitutes = (configs, testers = configs .map (makeTester)) => (sentence) =>
  Object.assign( ...testers .flatMap (({regex, propName}) => {
    const match = sentence .match (regex)
    return (match)
      ? {[propName]: match[1]}
      : {}
  }))

const configs = [{
  sample: 'covid-19 testing status upto may 05,2021',
  extract: 'may 05,2021',
  propName: 'date'
}, {
  sample: 'Jack and Jones are friends',
  extract: 'Jones',
  propName: 'friend-name'
}]

const mySubs = substitutes (configs)

console .log (mySubs ('Jack and William are friends'))
console .log (mySubs ('covid-19 testing status upto apr 30,2021'))
console .log (mySubs ('Jack and Jessica are friends who dicsussed covid-19 testing status upto apr 27,2021'))
console .log (mySubs ('Some random string that does not match'))
.as-console-wrapper {max-height: 100% !important; top: 0}

如果您还需要报告匹配的模板,您可以为每个模板添加一个名称,然后通过两个主要函数将结果携带到这样的结果:

{"covid": {"date": "apr 27,2021"}, "friends": {"friend-name": "Jessica"}}

只是稍微复杂一点:

const regEscape = (s) =>
  s .replace (/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');


const makeTester = ({name, sample, extract, propName}) => ({
  regex: new RegExp (
    regEscape (sample .slice (0, sample .indexOf (extract))) + 
    '(.+)' + 
    regEscape (sample .slice (sample .indexOf (extract) + extract .length))
  ),
  propName,
  name
})

const substitutes = (configs, testers = configs.map(makeTester)) => (sentence) =>
  Object.assign( ...testers .flatMap (({name, regex, propName}) => {
    const match = sentence .match (regex)
    return (match)
      ? {[name]: {[propName]: match[1]}}
      : {}
  }))

const configs = [{
  name: 'covid', 
  sample: 'covid-19 testing status upto may 05,2021',
  extract: 'may 05,2021',
  propName: 'date'
}, {
  name: 'friends',
  sample: 'Jack and Jones are friends',
  extract: 'Jones',
  propName: 'friend-name'
}]

const mySubs = substitutes (configs)

console .log (mySubs ('Jack and William are friends'))
console .log (mySubs ('covid-19 testing status upto apr 30,2021'))
console .log (mySubs ('Jack and Jessica are friends who dicsussed covid-19 testing status upto apr 27,2021'))
console .log (mySubs ('Some random string that does not match'))

无论如何,这都有一些限制。如果模板以奇怪的方式重叠等,很难弄清楚该怎么办。您也可能只想匹配完整的句子,而我的双重匹配示例没有意义。如果是这样,您可以在传递给new RegExp 的字符串前面加上一个'^' 并附加一个'$'。


同样,这是对您的要求的猜测。这里重要的是您可以动态生成正则表达式以供使用。

【讨论】:

    猜你喜欢
    • 2019-05-01
    • 2012-06-15
    • 2019-10-18
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 2015-12-31
    相关资源
    最近更新 更多