如何从重复的文本模式中提取内容?

时间:2018-06-15 06:40:10

标签: javascript regex

该文本是一系列患者记录的自定义序列化形式。

<PATIENTID>=1231
<PATIENTNAME>=ERICA
<PATIENTHISTORY>=MULTILINE TEXT
<KEYPOINTS>= ASTHMA, HBP, DIABETES
<PATIENTID>=1232
<PATIENTNAME>=NELSON
<PATIENTHISTORY>=MULTILINE TEXT
<KEYPOINTS>= JAUNDICE

我尝试使用以下正则表达式提取它,但它匹配整个字符串而不是每条记录。

const regEx= /^<PATIENTID>=(.)+<PATIENTNAME>=(.)+<PATIENTHISTORY>=(.)+<KEYPOINTS>=(.)+/g;

那么我应该如何改变正则表达式以迭代每条记录并提取相关字段?

5 个答案:

答案 0 :(得分:1)

您可以搜索左角和直角与其余部分之间的内容,直到找到不正确的角度,然后获取键和值对。

游乐场:https://regex101.com/r/sf5soM/1

var string = '<PATIENTID>=1231\n<PATIENTNAME>=ERICA\n<PATIENTHISTORY>=MULTILINE TEXT\n<KEYPOINTS>= ASTHMA, HBP, DIABETES\n<PATIENTID>=1232\n<PATIENTNAME>=NELSON\n<PATIENTHISTORY>=MULTILINE TEXT\n<KEYPOINTS>= JAUNDICE',
    regex = /<([^>]*)>=([^<]*)/gm,
    m,
    k, v;
    result = [];

while ((m = regex.exec(string)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    [, k, v] = m;

    if (k === 'PATIENTID') {
        result.push({});
    }
    result[result.length - 1][k] = v.trim();
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:0)

你可以只为每个数据进行子串。

var str = "<PATIENTID>=1231";
var afterComma = str.substr(str.indexOf("=") + 1); 

答案 2 :(得分:0)

/^<PATIENTID>=([\s\S]*?)<PATIENTNAME>=([\s\S]*?)<PATIENTHISTORY>=([\s\S]*?)<KEYPOINTS>=([\s\S]*?)(?=<PATIENTID>|$)/gm

https://regex101.com/r/DpSD1R/4

这里的主要内容是(?:\s|\S)组,确保您匹配空格和非空格字符......这意味着一切。与.(点)的区别在于它甚至会匹配换行符,并且您需要它,因为您的某些字段是多行的。

编辑:简化的非捕获组((?:\s|\S))与[\s\S]作为完全成熟的替代品并不是严格需要的。

编辑2:正如@Wiktor指出的,匹配应该在输入结束时或在另一个记录的开头结束。添加了具有正向前瞻(?=<PATIENTID>|$)的终端条件,也忘记了多行标记

答案 3 :(得分:0)

您可以捕获组^<([^>]+)>中尖括号之间的名称,然后匹配等号=,第二部分匹配所有字符,直到您在下一行遇到尖括号模式因为这是新比赛的开始。

这样您也可以匹配MULTILINE TEXT部分中的<>

<([^>]+)>=([\s\S]*?(?=^<[^[\r\n>]+>)|[\s\S]*)

解释

  • <([^>]+)>捕捉组中的尖括号(捕获组1)
  • 之间的内容
  • =按字面意思匹配
  • ([\s\S]*?将所有字​​符匹配为非贪婪的零次或多次
  • (?=^<[^[\r\n>]+>)断言后面的正面先行是行开头的尖括号模式
  • |
  • [\s\S]*匹配所有字符(您可以将其替换为.*以仅匹配整个最后一行而不是匹配所有字符)

&#13;
&#13;
const regex = /<([^>]+)>=([\s\S]*?(?=^<[^[\r\n>]+>)|[\s\S]*)/gm;
const str = `<PATIENTID>=1231
<PATIENTNAME>=ERICA
<PATIENTHISTORY>=MULTILINE TEXT
< with a line
with a line >
with a <> line
<> with a line
<KEYPOINTS>= ASTHMA, HBP, DIABETES
<PATIENTID>=1232
<PATIENTNAME>=NELSON
<PATIENTHISTORY>=MULTILINE TEXT
and this is a line
and this also
<KEYPOINTS>= JAUNDICE
and this is a line`;
let m, result = [];
while ((m = regex.exec(str)) !== null) {
  if (m.index === regex.lastIndex) {
    regex.lastIndex++;
  }
  if (m[1] === 'PATIENTID') {
    result.push({});
  }
  result[result.length - 1][m[1]] = m[2];
}
console.log(result);
&#13;
&#13;
&#13;

答案 4 :(得分:0)

根据我的想法,您可以使用其他一些功能并获得预期的结果。 希望这会有所帮助...

const text = `
  <PATIENTID>=1231
  <PATIENTNAME>=ERICA
  <PATIENTHISTORY>=MULTILINE TEXT
  <KEYPOINTS>= ASTHMA, HBP, DIABETES
  <PATIENTID>=1232
  <PATIENTNAME>=NELSON
  <PATIENTHISTORY>=MULTILINE TEXT
  <KEYPOINTS>= JAUNDICE
`;

const test = text.replace(/<PATIENT/g, ';').replace(/>=/g, ':').replace(/<KEYPOINTS/g, 'KEYPOINTS').split(';');
const ObjectList = [];

test.map((t) => {
  const text = t.trim();
  const finalText = text.replace(/\r?\n|\r/g, ';').split(';').map(a => a.trim());
  if(finalText) {
    finalText.forEach(item => item && ObjectList.push(item));
  }
});

console.log(ObjectList);

// output: ["ID:1231",
            "NAME:ERICA",
            "HISTORY:MULTILINE TEXT",
            "KEYPOINTS: ASTHMA, HBP, DIABETES",
            "ID:1232",
            "NAME:NELSON",
            "HISTORY:MULTILINE TEXT",
            "KEYPOINTS: JAUNDICE"
            ]