根据分隔符

时间:2017-08-28 12:20:14

标签: javascript jquery regex string substring

我正在尝试从编码的二维条码中提取数据。提取部分工作正常,我可以在文本输入中获取值。

,例如,解码后的字符串是

] D2的 01 05000456013482的 17 201200的 10 00001 /:的 21 0000000001

基于以下规则(无法获得正确的表格标记,从而附加图片),我试图从上面提到的字符串中提取子字符串。

enter image description here

我想提取的子字符串:

05000456013482(在分隔符01之后)

201200(在分隔符17之后)

<00> 00001(在分隔符10之后)

0000000001(在分隔符21之后)

P.S - &gt;原始字符串中的前3个字符(]d2)总是相同的,因为它只是简单地表示解码方法。

现在有些怪癖:

1)分隔符10后面的字母数不固定。因此,在上面给出的示例中,即使它是00001,它也可能是001。类似地,分隔符21之后的字母数也不固定,并且可以具有不同的长度。

对于不同长度的分隔符,我添加了一个常量/:,以确定在扫描手持设备后编码何时结束。

现在,我在分隔符10之后查找/:并提取字符串,直到它到达/:或EOL并找到分隔符21并删除字符串,直到它到达/:或EOL

2)分隔符0117后的字母数始终是固定的(分别为14个字母和6个字母),如表所示。

注意:分隔符的位置可能会发生变化。换句话说,编码的条形码可以用不同的顺序编写。

] d2 01 05000456013482 17 201200 10 00001 /: 21 0000000001 - 注意:否{{1因为它是EOL

,所以在21组之后签名

] d2 17 201200 10 00001 /: 21 0000000001 /: 01 05000456013482 - 注意:两者均为10和21组有/:符号表示我们必须提取,直到该符号

] d2 10 00001 /: 21 0000000001 /: 01 05000456013482 17 201200 - 前两个是长度变化,接下来两个是固定长度。

我不是正则表达式的专家,到目前为止我只尝试使用像/.这样的简单模式,这些模式在给定的示例中不起作用,因为它像前两个字符一样查找10。此外,使用(01)(\d*)(21)(\d*)(10)(\d*)(17)(\d*)$方法仅适用于固定长度字符串的情况,当我知道我必须采用哪些索引时。

P.S - 赞赏JS和jQuery帮助。

2 个答案:

答案 0 :(得分:1)

好的,这是我对此的看法。我创建了一个匹配所有可能模式的正则表达式。这样,所有部件都被正确拆分,剩下的就是使用前两位数字来了解它的含义。

^\]d2(?:((?:10|21)[a-zA-Z0-9]{1,20}(?:\/:|$))|(01[0-9]{14})|((?:11|15|17)[0-9]{6}))*

我建议你把它复制到regex101.com来阅读完整的描述符并根据不同的可能结果进行测试。

有3个电源部分:

((?:10|21)[a-zA-Z0-9]{1,20}(?:\/:|$))

对从10和21开始的部分进行哪些测试。它查找1到20次之间的字母数字实体。它应以EOL/:

结尾
(01[0-9]{14})

查找GTIN,非常简单。

((?:11|15|17)[0-9]{6})

查找3个日期字段。

由于我们预计这三个细分市场会以任何顺序排列,我会将它们粘在一起暗示一个OR并期望这个大序列重复(最后*表示0或更多,我们可以定义确切的最小值和最大值以获得更高的可靠性)

我不确定这是否适用于所有内容,因为您提供的测试字符串不包含实际值中的标识符...很可能恰好在产品的最佳日期之前是1月,因此其中将有一个01值。但是强制正则表达式以这种方式执行应该可以避免其中的一些问题。

编辑:捕获组只捕获最后一次出现,因此我们需要拆分它们的定义:

^\]d2(?:(21[a-zA-Z0-9]{1,20}(?:\/:|$))|(10[a-zA-Z0-9]{1,20}(?:\/:|$))|(01[0-9]{14})|(11[0-9]{6})|(15[0-9]{6})|(17[0-9]{6}))*

再次编辑:Javascript似乎让我们感到头痛......我不确定处理它的正确方法,但这里有一个可行的示例代码。

var str = "]d20105000456013482172012001000001/:210000000001";
var r = new RegExp("(21[a-zA-Z0-9]{1,20}(?:\/:|$))|(10[a-zA-Z0-9]{1,20}(?:\/:|$))|(01[0-9]{14})|(11[0-9]{6})|(15[0-9]{6})|(17[0-9]{6})", "g");
var i = 0;
while ((match = r.exec(str)) != null) {
  console.log(match[0]);
}

我对它的结果并不十分满意。可能有更好的解决方案。

答案 1 :(得分:1)

虽然您可以尝试制作一个非常复杂的正则表达式来执行此操作,但是在步骤中解析字符串会更具可读性和可维护性。

基本步骤是:

  1. 删除解码方法字符(] d2)。
  2. 从步骤1的结果中拆分前两个字符。
  3. 使用它来选择提取数据的方法
  4. 从字符串中删除并保存该数据,转到步骤2重复,直到用完字符串。
  5. 现在,由于您有一个AI /数据结构表,您可以使用几种方法来提取不同形式的数据

    例如,由于AI:01,11,15,17都是固定长度,你可以使用长度为

    的字符串切片方法
    str.slice(0,14); //for 01
    str.slice(0,6);  //for 11 15 17
    

    虽然像AI 21这样的可变类似于

    var fnc1 = "/:";
    var fnc1Index = str.indexOf(fnc1);
    str.slice(0,fnc1Index);
    

    演示

    &#13;
    &#13;
    var dataNames = {
      '01': 'GTIN',
      '10': 'batchNumber',
      '11': 'prodDate',
      '15': 'bestDate',
      '17': 'expireDate',
      '21': 'serialNumber'
    };
    
    var input = document.querySelector("input");
    document.querySelector("button").addEventListener("click",function(){
      var str = input.value;
      console.log( parseGS1(str) );
    });
    
    function parseGS1(str) {
      var fnc1 = "/:";
      var data = {};
      
      //remove ]d2
      str = str.slice(3);
      while (str.length) {
        //get the AI identifier: 01,10,11 etc
        let aiIdent = str.slice(0, 2);
        //get the name we want to use for the data object
        let dataName = dataNames[aiIdent];
        //update the string
        str = str.slice(2);
    
        switch (aiIdent) {
          case "01":
            data[dataName] = str.slice(0, 14);
            str = str.slice(14);
            break;
          case "10":
          case "21":
            let fnc1Index = str.indexOf(fnc1);
            //eol or fnc1 cases
            if(fnc1Index==-1){
              data[dataName] = str.slice(0);
              str = "";
            } else {
              data[dataName] = str.slice(0, fnc1Index);
              str = str.slice(fnc1Index + 2);
            }
            break;
          case "11":
          case "15":
          case "17":
            data[dataName] = str.slice(0, 6);
            str = str.slice(6);
          break;
          default:
            console.log("unexpected ident encountered:",aiIndent);
            return false;
            break;
        }
      }
      return data;
    }
    &#13;
    <input><button>Parse</button>
    &#13;
    &#13;
    &#13;