JS NLP工具如何从自然文本中提取时间及时区?
能识别带时区时间的JavaScript库推荐
针对你遇到的chrono和WinkNLP忽略时区信息的问题,以下几个方案可以实现提取带时区的时间实体需求:
1. Luxon + 自定义正则匹配
Luxon是一个强大的日期处理库,原生支持时区解析。你可以先通过正则提取文本中的时间和时区部分,再用Luxon组合解析:
const { DateTime } = require('luxon'); const text = `The release happened on 21 August 2020 at 4:32 pm Eastern time`; // 匹配时间+时区的正则(可根据需求扩展) const timeZoneRegex = /(\d{1,2}:\d{2}\s?(?:am|pm))\s?([A-Za-z\s]+time|GMT[+-]\d+)/i; const match = text.match(timeZoneRegex); if (match) { const [, timePart, tzPart] = match; // 映射常见时区名称到IANA时区标识 const tzMap = { 'Eastern time': 'America/New_York', 'UK Time': 'Europe/London', 'New York Time': 'America/New_York', 'GMT-4': 'Etc/GMT+4' // 注意Luxon中GMT-4对应Etc/GMT+4,因为Etc时区是反向的 }; const tz = tzMap[tzPart.trim()] || tzPart; // 组合日期和时间,解析为带时区的DateTime对象 const fullDateTime = DateTime.fromFormat(`21 August 2020 ${timePart}`, 'dd MMMM yyyy h:mm a', { zone: tz }); console.log('带时区的时间:', fullDateTime.toFormat('yyyy-MM-dd h:mm a z')); // 输出:2020-08-21 4:32 pm EDT }
2. Natural 自定义实体识别
Natural是Node.js生态的NLP库,支持自定义实体提取规则。你可以配置时区相关的实体词典,让它识别出时间和时区:
const natural = require('natural'); const { DateTime } = require('luxon'); const tokenizer = new natural.WordTokenizer(); const text = `The release happened on 21 August 2020 at 4:32 pm Eastern time`; const tokens = tokenizer.tokenize(text); // 定义时区词典 const timeZoneDict = new natural.Lexicon(); const timeZoneRules = new natural.RuleSet(); timeZoneDict.add('Eastern time', 'TIME_ZONE'); timeZoneDict.add('UK Time', 'TIME_ZONE'); timeZoneDict.add('GMT-4', 'TIME_ZONE'); timeZoneDict.add('New York Time', 'TIME_ZONE'); const classifier = new natural.BayesClassifier(timeZoneDict, timeZoneRules); // 提取时间和时区 let timePart = ''; let tzPart = ''; tokens.forEach(token => { if (token.match(/\d{1,2}:\d{2}/) || token.match(/am|pm/i)) { timePart += ` ${token}`; } const classification = classifier.classify(token); if (classification === 'TIME_ZONE') { tzPart += ` ${token}`; } }); timePart = timePart.trim(); tzPart = tzPart.trim(); // 用Luxon解析 const tzMap = { 'Eastern time': 'America/New_York', 'UK Time': 'Europe/London', 'New York Time': 'America/New_York', 'GMT-4': 'Etc/GMT+4' }; const fullDateTime = DateTime.fromFormat(`21 August 2020 ${timePart}`, 'dd MMMM yyyy h:mm a', { zone: tzMap[tzPart] }); console.log('带时区的时间:', fullDateTime.toFormat('yyyy-MM-dd h:mm a z'));
3. date-fns-tz + 实体提取
date-fns-tz是date-fns的时区扩展,用法类似Luxon,先提取时间和时区再组合:
const { format, parse } = require('date-fns'); const { formatInTimeZone } = require('date-fns-tz'); const enUS = require('date-fns/locale/en-US'); const text = `The release happened on 21 August 2020 at 4:32 pm Eastern time`; const match = text.match(/(\d{1,2}:\d{2}\s?(?:am|pm))\s?([A-Za-z\s]+time|GMT[+-]\d+)/i); if (match) { const [, timePart, tzPart] = match; const tzMap = { 'Eastern time': 'America/New_York', 'UK Time': 'Europe/London', 'New York Time': 'America/New_York', 'GMT-4': 'Etc/GMT+4' }; const date = parse(`21 August 2020 ${timePart}`, 'dd MMMM yyyy h:mm a', new Date(), { locale: enUS }); console.log('带时区的时间:', formatInTimeZone(date, tzMap[tzPart], 'yyyy-MM-dd h:mm a zzzz')); }
这些方案的核心是先提取时间和时区实体,再用专业日期库解析带时区的时间,因为纯NLP库通常不会默认将时区与时间绑定为一个实体,需要结合规则或自定义配置来实现。
内容的提问来源于stack exchange,提问作者No Name
相关产品推荐
相关产品推荐

