2017-09-14 249 views
1

我試圖從字符串中提取數字組。 這些數字既可以單獨使用,也可以作爲\d+ - \d+格式的範圍,而兩個數字之間的範圍指示符可以不同,並且數字可以使用前綴M-STR。這些組可以在給定的字符串中出現1到n次,但是如果一個組後面跟着任何不是數字,空格或上面提到的前綴之一的字符,則匹配應該停止,即使後面還可以找到更多的數字。全局正則表達式匹配停止中間字符串

作爲一個例子,下面幾行

01 
05,07 
05, 7 
M-01, M-12 
311,STR 02 
M-56 
STR 17 
01 - Random String 25-31 Random other string 
M-04 Random String 01 
M-17,3,148,14 to 31 
M-17,3,STR 148,14 to 31 - Random String 
M-17,3,148,14- 31 Random, String 02 Random, other string 
STR 17,3,12 to 18, 148 ,M-14- 31 : Random String 02 

應該返回

01 
05;07 
05;7 
01;12 
311;02 
56 
17 
01 
04 
17;3;148;14 to 31 
17;3;148;14 to 31 
17;3;148;14- 31 
17;3;12 to 18;148;14- 31 

我使用javascript和運行

var pattern = /(\d+)\s?(?:-|~|to)?\s?(\d+)?/ig 
while (result = pattern.exec(line)) {console.log(result)} 

,但我幾乎可以得到正確的結果不知道如何在第一個字符串後不匹配數字,即M-17,3,148,14 to 31 - Random string 46 Random string將retu值17;3;148;14 to 31;46,而46不應該匹配。

我並不是真的擔心結果的格式,因爲我無論如何正在消毒它們,因此'03 '返回爲'03''03 '並不重要。對於數字範圍也是如此,15 - 17既可以作爲15 - 17返回,也可以如上例所示,使用捕獲組來確定上限和下限,但我仍然需要能夠判斷兩個數字是分開還是範圍,所以5,8,10-12不能作爲5;8;10;12返回。

我的最終目標是提取每行中的所有可能的值。在提取所有數字範圍後,我循環遍歷每個結果以獲得所有可能的值,例如, 5,8,10-12將變成5; 8; 10; 11; 12。

如果它在某種程度上是可能的,而且這純粹是可選的,我還想在最後一個數字範圍後保留字符串,例如, STR 14, 23 Some String 18 Some other string應返回14;23並單獨返回Some String 18 Some other string

如果有人有關於如何解決這個問題的想法,我將不勝感激。

回答

0

這是我的嘗試。

[ 
 
    '01', 
 
    '05,07', 
 
    '05, 7', 
 
    'M-01, M-12', 
 
    '311,STR 02', 
 
    'M-56', 
 
    'STR 17', 
 
    '01 - Random String 25-31 Random other string', 
 
    'M-04 Random String 01', 
 
    'M-17,3,148,14 to 31', 
 
    'M-17,3,STR 148,14 to 31 - Random String', 
 
    'M-17,3,148,14- 31 Random, String 02 Random, other string', 
 
    'STR 17,3,12 to 18, 148 ,M-14- 31 : Random String 02', 
 
    '14 ~ 16', 
 
    'Random String 15', 
 
    '1to3', 
 
    'M-01 to STR 6', 
 
    '17 56' 
 
].forEach(function(str) { 
 
    var rangeRe = /(?:\s*,\s*)(?:M-|STR)?(\d+)(?:\s*(?:-|~|to)\s*(\d+))?/g, 
 
     ranges = [], 
 
     lastIndex = 1, 
 
     match; 
 

 
    str = ',' + str; 
 

 
    while (match = rangeRe.exec(str)) { 
 
     // Push a lower and upper bound onto the list of ranges 
 
     ranges.push([+match[1], +(match[2] || match[1])]); 
 

 
     lastIndex = rangeRe.lastIndex; 
 
    } 
 

 
    // Log the original string, the ranges and the remainder 
 
    console.log([ 
 
     str.slice(1), 
 
     ranges.map(function(pair) { 
 
      return pair[0] + '-' + pair[1]; 
 
     }).join(' ; '), 
 
     str.slice(lastIndex) 
 
    ]); 
 
});

這裏是我遵循的規則:

  • 數由連續的數字。
  • 範圍由一個數字或一對數字組成。
  • 如果一個範圍有一對特徵,則它們可以用-,~to分開,在分隔符的任一側加上任意的空格。
  • 範圍(備註範圍,不是數字)可以用M-STR作爲前綴。前綴和範圍之間不允許有額外的空格。
  • 範圍由,加上,任意一邊的任意空格分開。

將每個範圍解析爲由下限和上限組成的數組對。對於單數範圍,兩個邊界使用相同的值。

我已經使用了exec的狀態。循環的每次迭代都開始匹配上次匹配停止的地方。跟蹤lastIndex,以便我們可以在最後生成剩餘的「隨機字符串」。

在我開始之前,我在字符串的前面添加了一個,。這使得RegExp可以假定所有的範圍都以,開頭,避免了第一範圍的特殊情況。

與您發佈的某些RegExps的主要區別在於,我將整個「範圍分隔符和上限」部分作爲一個單元進行了選擇,而不是單獨使其成爲可選項。這樣做的結果是,像17 56這樣的輸入將被視爲「隨機字符串」而不是作爲上限的56。範圍將被視爲17-17。

+0

這工作非常好。比我原來的解決方案好得多。非常感謝您的努力! – mmuffins

0

因此,獲得了咖啡後,我想我找到了接近解決方案的東西:

function extractNumbers(line){ 
    var str = line.replace(/(?:M-\s?|STR)(\d+)/ig,'$1') 
    var rightpart = str.match(/([a-x].*)/i) 
    var leftpart = str.replace(rightpart[1],'') 
    var pattern = /(\d+)\s?(?:-|~|to)?\s?(\d+)?/ig 
    while (result = pattern.exec(leftpart)) {console.log(result)} 
    console.log(rightpart[1]) 
} 

此功能輸出的所有號碼的範圍,然後串到控制檯的其餘部分。有可能出現誤報,因爲它首先替換M-和STR後面跟着一個數字的所有出現,即使它們出現在字符串的右邊部分。這個確切的字符序列發生在右側部分的機會可能很小,但仍然...

如果有人對原始問題或如何消除誤報機會的想法有一個答案,我會愛上看見了。