【问题标题】:Extracting substring based on a single or double digit character using javascript使用javascript提取基于单个或双位字符的子字符串
【发布时间】:2017-08-30 08:51:12
【问题描述】:

这是一个基于我之前提出的问题Extracting substring from string based on delimiter(已接受答案)的新问题

我有一个字符串]d1[)½}06~9N110375286414~1T12345ABCD~D150600~S12345ABCDEF98765}

注意:上例中}后面有个空格

我在上述字符串上的分隔符是 9N、1T、D、S,我需要提取分隔符之后的子字符串,直到它达到~ 或 EOL。

在下面的小提琴中,它期望 D1S1 作为分隔符,而不是分别使用 DS

我面临 2 个问题

1) 单字符分隔符问题(DS

2) 返回值时,我应该如何在字符串末尾去掉}。例如,带有分隔符S 的子字符串应该返回12345ABCDEF98765 而不是12345ABCDEF98765}

Fiddle(结果基于控制台)

JS

// Use ]d1[)½}06~9N110375286414~1T12345ABCD~D150600~S12345ABCDEF98765} 
// Note: There is an empty space after the } char as shown above

var dataNames = {
  '9N': 'PPN',
  '1T': 'batchNumber',
  'D': 'expireDate',
  'S': '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 ]d1[)½}06~
  str = str.slice(10);

  while (str.length) {
    //get the AI identifier: 1T, 9N 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 "1T":
      case "9N":
        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 + 1);
        }
        break;
      case "D":
      case "S":

        //eol or fnc1 cases

        break;
      default:
        console.log("unexpected ident encountered:", aiIdent);
        return false;
        break;
    }
  }
  return data;
}

【问题讨论】:

    标签: javascript string substring


    【解决方案1】:

    您也可以使用正则表达式来执行此操作。使用此解决方案,当部分字符串被移动时,它仍然可以工作。

    function getData(input) {
      input = input.slice(0, input.length - 2);
      // The regex has two capture groups. 
      // Group 1 gets the identifier, this can also be the start of the string.
      // Group 2 gets all the characters between the identifier and the '~' char or '} '.
      // The third group is a non-capturing group, it is used to find the delimiter where the next part starts.
      var
          regex = /(^|9N|1T|D|S)(.*?)(?:~|$)/g,
          data = {},
          match = regex.exec(input);
    
      while (match !== null) {
        switch(match[1]) {
        case '9N':
          data.PPN = match[2];
          break;
        case '1T':
          data.batch = match[2];  
          break;
        case 'D':
          data.expireDate = match[2];  
          break;
        case 'S':
          data.serial = match[2];  
          break;  
        }
        var msg = 'Found ' + match[0] + ' / identifier = ' + match[1]  +  ' / value = ' + match[2] + '. ';
        console.log(msg);
    
        // Get the next match.
        match = regex.exec(input);
      }
      return data;
    }
    
    var input = ']d1[)½}06~9N110375286414~1T12345ABCD~D150600~S12345ABCDEF98765} ',
        input2 = ']d1[)½}06~9N110375286414~D150600~1T12345ABCD~S12345ABCDEF98765} ';
    console.log(getData(input));
    console.log(getData(input2));

    【讨论】:

    • 太棒了。非常感谢!
    • 有什么方法可以让我总是跳过最后 2 个字符。在我给定的示例中,它是 } 但是,我想总是跳过最后 2 个字符。
    • input = input.slice(0, input.length - 2);
    • 我保持正则表达式不变?
    • 删除最后一个字符时,也需要更改正则表达式。我已经更新了答案以反映这一点。
    【解决方案2】:

    在您的示例中,~ 位于子字符串的末尾,并且位于分隔符的开头。

    因此,您可以使用~ 作为分隔符本身的一部分,并在正则表达式中使用~9N~1T 等来拆分字符串。这解决了单个字符分隔符的问题,因为 DS 现在变为 ~D~S

    通过匹配正则表达式中的} 并通过不将其捕获为~S 之后的子字符串的一部分从输出中消除它来解决第二个问题。

    示例代码:

    // your input
    var str = ']d1[)½}06~9N110375286414~1T12345ABCD~D150600~S12345ABCDEF98765} ';
    
    // regex to parse delimiters
    var pattern = /(.*)~9N(.*)~1T(.*)~D(.*)~S(.*)\}/;
    
    // delimiter descriptions
    var dataNames = {
      '9N': 'PPN',
      '1T': 'batchNumber',
      'D': 'expireDate',
      'S': 'serialNumber'
    };
    
    // test input
    console.log(parseGS1(str));
    
    // parse function
    function parseGS1(str) {
      // call regex
      var match = pattern.exec(str); // try console.log(match);
    
      // output object
      var data = {};
      
      // match items 2-5 should be substrings
      data[dataNames['9N']] = match[2];
      data[dataNames['1T']] = match[3];
      data[dataNames['D']] = match[4];
      data[dataNames['S']] = match[5];
      
      return data;
    }

    【讨论】:

    • 这里的问题是,如果我切换序列,正则表达式将不起作用。例如,如果在末尾放置 9N 分隔符而不是 S 分隔符。
    • @zaq 看看我的解决方案,它使用正则表达式但没有这个问题。
    • @Thijs 是的,您的解决方案有效。我只是想在此评论中报告它,以便 Robin 可以使答案变得更好和更普遍。
    【解决方案3】:

    如果您的字符串始终具有您在问题中显示的格式,您可以在 ~ 符号处拆分字符串,然后只检查子字符串的前 2 个字符。

    var string = "]d1[)½}06~9N110375286414~1T12345ABCD~D150600~S12345ABCDEF98765} "
    
    var substrings = string.split('~');
    substrings.shift(); //get rid of irrelevant first array element
    substrings[substrings.length-1] = substrings[substrings.length-1].replace("} ", "");
    

    上面示例中的替换消除了末尾的花括号。但我不完全确定这是否是最优雅的方式。它肯定不是最灵活的,所以如果你在末尾遇到大括号 + 空格以外的任何内容,它当然不会被删除。

    提取这些子字符串并删除第一个数组元素后,您可以专注于仅检查字符串中的第一个字符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-05
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      • 1970-01-01
      • 2017-02-15
      • 2010-12-28
      • 1970-01-01
      相关资源
      最近更新 更多