2017-08-07 112 views
0

在JavaScript中,我正在尋找一個正則表達式來捕獲字符串中的多個可選組。但至少有一個組應該存在。正則表達式:使用單個匹配捕獲多個可選組

字符串:foo bar 12 seconds 3minutes 4h

正則表達式到目前爲止:/(?:(\d+)\s?s(?:econds?)?)?(?:(\d+)\s?m(?:inutes?)?)?(?:(\d+)\s?h(?:ours?)?)?/gi

我需要捕捉12 seconds3minutes4h,只返回在各自小組的數值。

這些時間單位可以存在或交換。我的最終結果將需要看起來像這樣:

12s 3m //['12', '3', undefined] 
10 seconds //['10', undefined, undefined] 
4hours //[undefined, undefined, '4'] 
3 minutes //[undefined, '3', undefined] 
1hour 54seconds 7minutes //['54', '7', '1'] 

undefinednull甚至一個空字符串。只要他們在各自的指數。

任何簡單的方法來處理這與一個execmatch而不使用循環?

+0

不,沒有這樣的方式,最乾淨的將運行3個單獨的正則表達式,並以您想要的方式安排匹配。 –

+0

同意@WiktorStribiżew。 12和秒之間的空間有效?我問,因爲秒,分鐘和小時的格式看起來不同(空格) – JBone

+0

@JBone是的,它是有效的。這些字符串由用戶編寫。有些使用空間,有些則不使用。所以正則表達式說明了這一點。 – Marian

回答

1

由於Wiktor正確指出,沒有辦法用一個正則表達式來做到這一點。這裏是一個實現一個3-正則表達式溶液的簡單函數:

function get_time_parts(text) { 
    var s, m, h; 
    // Seconds part: Either "s", "sec", "secs" "second" or "seconds". 
    s = text.match(/\b(\d+)\s*s(?:ec(?:ond)?s?)?\b/i); 
    s = s ? s[1] : undefined; 
    // Minutes part: Either "m", "min", "mins" "minute" or "minutes". 
    m = text.match(/\b(\d+)\s*m(?:in(?:ute)?s?)?\b/i); 
    m = m ? m[1] : undefined; 
    // Hours part: Either "h", "hr", "hrs" "hour" or "hours". 
    h = text.match(/\b(\d+)\s*h(?:rs?|ours?)?\b/i); 
    h = h ? h[1] : undefined; 
    return (s || m || h) ? [s, m, h] : null; 
} 

正如在註釋中規定,該功能允許以下部分時間的變化:

秒部分:或者「S」,「秒」 ,「秒」,「秒」或「秒」。
分鐘部分:「m」,「min」,「mins」,「分鐘」或「分鐘」。
小時部分:「h」,「hr」,「hrs」「小時」或「小時」。

正則表達式不區分大小寫,因此會允許變化,例如, HR,Sec,mIN等如果沒有任何部分存在,則該函數返回null。

-1

不知道這與您匹配的各種類型的輸入字符串,但這裏是我想出了你輸入字符串的東西。我假設秒數先到達,然後是分鐘,然後是小時,因爲您已在問題輸入字符串中找到它。此訂單是否始終正確?

let str = "foo bar 12 seconds 3minutes 4h"; 
let result = str.match(/(\d+) ?(?:sec|seconds) ?(\d+) ?(?:min|minutes) ?(\d+) ?(?:h|hours?)/); 
console.log(`${result[3]}hour ${result[1]}second ${result[2]}minutes`); 
+0

此解決方案不能用作@Marian發佈的正則表達式 - 如果刪除其中一個時間單位,則您的正則表達式將不起作用。例如,字符串'foo bar 12a secondds 5m 4h'將強制執行錯誤。 – archos

1

有沒有簡單的解決方案,用普通的正則表達式做到這一點。最簡單的解決方案是使用exec方法並將值設置爲散列(對象)。此外,你可以簡化你的正則表達式 - 所有工程,第二,我們的是完全無用的正則表達式。如果你只想要s你應該使用(?:s|second),因爲在你的例子中5樣品也會匹配。

您的問題,最簡單的解決方案(不處理單元的順序):

var str = "foo bar 12 seconds 5m 4hours"; 
 
var re = /(\d+)\s*([smh])/gi 
 
var hash = {}; 
 

 
var m; 
 
while ((m = re.exec(str)) !== null) { 
 
    // get values 
 
    var value = m[1]; 
 
    var unit = m[2].toLowerCase(); 
 

 
    // set value 
 
    hash[unit] = value; 
 
} 
 

 
console.log(hash);

該解決方案將始終使用最後一個出現,也不會依賴的順序上單位。

+0

是的,這將簡化我的正則表達式,因爲它以_s_開始,所以(':?秒|?)?或'(?:s | second)'仍然會匹配_5個samples_。 但無論如何,這有助於。謝謝。 – Marian