这是一个基于我之前提出的问题Extracting substring from string based on delimiter(接受答案)的新问题
我有一个字符串]d1[)½}06~9N110375286414~1T12345ABCD~D150600~S12345ABCDEF98765}
注意:上例中的}
后面有空格
我对以上字符串的分隔符是9N,1T,D,S,我需要在分隔符后提取子字符串,直到它达到~
或EOL。
在下面的小提琴中,期望分别为D1
和S1
作为分隔符,而不是D
和S
。
我面临两个问题
1)单个字符分隔符问题(D
,S
)
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;
}
答案 0 :(得分:3)
您也可以使用正则表达式执行此操作。使用此解决方案,当部分字符串移动时,它仍然可以工作。
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));

答案 1 :(得分:0)
如果您的字符串始终具有您在问题中显示的格式,则可以将字符串拆分为〜符号,然后仅检查子字符串的前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("} ", "");
上述例子中的替换消除了最后的花括号。但我不完全确定这是否是最优雅的方式。肯定不是最灵活的,所以如果你最后面对大括号+空格以外的任何东西,它当然不会被删除。
在提取这些子字符串并删除第一个数组元素之后,您可以专注于只检查字符串中的第一个字符。
答案 2 :(得分:0)
在您的示例中,~
位于子字符串的末尾,它也位于分隔符的开头。
因此,您可以将~
用作分隔符本身的一部分,并在正则表达式中使用~9N
,~1T
等来分割字符串。这解决了单个字符分隔符的问题,因为D
和S
现在变为~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;
}