2013-02-03 31 views
0

我試圖匹配包含和絃的行,但我需要確保每個匹配都被空白或首行所包含而不消耗字符,因爲我不希望它們返回給調用者。如何讓我的正則表達式匹配空白而不消耗它們?

E.g.

Standard Tuning (Capo on fifth fret) 

Time signature: 12/8 
Tempo: 1.5 * Quarter note = 68 BPM 

Intro: G Em7 G Em7 

    G     Em7 
I heard there was a secret chord 
    G     Em7 
That David played and it pleased the lord 
    C    D    G/B  D 
But you don't really care for music, do you? 
     G/B    C   D 
Well it goes like this the fourth, the fifth 
    Em7     C 
The minor fall and the major lift 
    D   B7/D#   Em 
The baffled king composing hallelujah 

Chorus: 

G/A G/B C   Em   C    G/B D/A G 
Hal - le- lujah, hallelujah, hallelujah, hallelu-u-u-u-jah .... 

除了它也匹配「68 BPM」中的「B」以外,幾乎可以工作。現在我該如何確保和絃正確匹配?我不希望它匹配之前的B或SUBSIDE中的D或E?

這是我在每個單獨的行匹配算法:

function getChordMatches(line) { 
    var pattern = /[ABCDEFG](?:#|##|b|bb)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[ABCDEFG](?:#|##|b|bb)?)?/g; 
    var chords = line.match(pattern); 
    var positions = []; 
    while ((match = pattern.exec(line)) != null) { 
     positions.push(match.index); 
    } 

    return { 
     "chords":chords, 
     "positions":positions 
    }; 
} 

即我想要的形式[ 「A」, 「BM」, 「C#」]而不是[ 「A」 上的陣列, 「Bm」,「C#」]。

編輯

我做了它的工作使用公認的答案。我不得不做一些調整來適應領先的空白。感謝您花時間每個人!

function getChordMatches(line) { 
    var pattern = /(?:^|\s)[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?(?!\S)/g; 
    var chords = line.match(pattern); 
    var chordLength = -1; 
    var positions = []; 

    while ((match = pattern.exec(line)) != null) { 
     positions.push(match.index); 
    } 

    for (var i = 0; chords && i < chords.length; i++) { 
     chordLength = chords[i].length; 
     chords[i] = chords[i].trim(); 
     positions[i] -= chords[i].length - chordLength; 
    } 

    return { 
     "chords":chords, 
     "positions":positions 
    }; 
} 
+0

除了你的空白問題,你確定該模式是足夠的嗎?那麼和F13#11或C7b9或G11no3rd一樣的和絃呢? – nnnnnn

+0

@nnnnnn你說得對。它不會匹配那些和絃。然而,我從來沒有遇到過這樣的事情(爵士樂和絃?),所以我必須調整模式,如果我需要他們。 – MdaG

+0

那麼你很可能會看到像爵士樂表上的那些和絃,但真正和平9的和絃不是那麼晦澀。我曾經在搖滾樂中看過「E no 3rd」之類的東西,雖然有時會用圓括號表示「E(第三)」。 – nnnnnn

回答

1

我假設你已經把輸入分成了幾行。該函數將逐行處理這些行。

你只需要檢查該線具有和絃作爲第一個項目提取他們面前:

if (/^\s*[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?(?!\S)/.test(line)) { 
    // Match the chords here 
} 

我在前面加^\s*從行的開頭進行檢查,並添加(?!\S)檢查在第一個和絃之後有一個空白字符\s或行尾。

請注意,我對您的正則表達式做了一些小的修改,因爲A##(假設它是有效的和絃)將不會與您當前的正則表達式匹配。正則表達式引擎會根據交替模式的順序來檢查匹配,所以#將首先在#|##中嘗試。它會發現A#匹配並返回匹配,但未檢查##。要麼顛倒訂單##|#要麼使用貪婪量詞##?修復問題,因爲它首先檢查更長的替代方案。


如果你確信:「如果第一個項目是一個和絃,然後其餘的都是和絃」,然後,而不是匹配,你可以用空格分開:

line.split(/\s+/); 

更新

如果你想只匹配你的模式,不管是否弦是一個句子裏(你現在有能做到這一點):

/(?:^|\s)[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?(?!\S)/ 

這個正則表達式將被放置在你的問題中的代碼。

我檢查和絃前面是空格字符還是(?:^|\s)的行首。不過,您需要修剪結果中的前導空格。

使用\b而不是(?:^|\s)將避免導致空間問題,但含義不同。除非你足夠了解投入,否則我會反對。


另一種方式是通過\s+到分割字符串,並測試下面的正則表達式對每一個令牌(注意^在開始和$在末端):

/^[A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:##?|bb?)?)?$/ 
+0

一旦確定了帶有和絃的線條,就可以在白色空間上進行分割。但爲什麼原來的正則表達式不匹配「A ##」? – nnnnnn

+0

@nnnnnn:由於正則表達式引擎在###之前選擇了'#'(它將遵循交替的順序),它會認爲'A#'匹配。 '##?',''''貪婪,或'## |#'會在'A#'之前檢查'A ##',所以如果你有'A ##'',## ##'或'## |#'將正確匹配。 – nhahtdh

+0

哦,對,這是有道理的。謝謝。 – nnnnnn

0

添加\b (字邊界)到開始和結束爲我工作。此外,您可以使用A-G而不是ABCDEFG。因此:

> re = /\b[A-G](?:#|##|b|bb)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:#|##|b|bb)?)?\b/g 
/\b[A-G](?:#|##|b|bb)?(?:min|m)?(?:maj|add|sus|aug|dim)?[0-9]*(?:\/[A-G](?:#|##|b|bb)?)?\b/g 

> 'G/A G/B C   Em   C    G/B D/A G'.match(re) 
["G/A", "G/B", "C", "Em", "C", "G/B", "D/A", "G"] 

> 'Tempo: 1.5 * Quarter note = 68 BPM'.match(re) 
null 
+0

-1字邊界將導致'A#'失敗。 – nhahtdh

+0

@nhahtdh - 良好的捕獲。 – broofa

0

在回答標題中的具體問題,提前使用一下:

(?=\s) 

嵌入時在RE將確保後面的字符是一個空白,而無需耗費它。

+0

如果和絃在最後(沒有空格)正確,它可能不起作用。 – nhahtdh

+0

@HBP我已經試過了,正如上面提到的那樣,它修復了這個問題,但創建了另一個和換行符之後的和絃不匹配的地方。 – MdaG

+0

@MdaG爲什麼不添加一些OR運算符?:'(?= \ s | \ r | \ n)' – rcdmk

0

請嘗試以下

function getChordMatches(line) { 
    var match, 
     pattern = /(?:^|\s)([A-G](?:##?|bb?)?(?:min|m)?(?:maj|add|sus|aug|dim)?\d*(?:\/[A-G](?:##?|bb?)?)?)(?=$|\s)/g, 
     chords = [], 
     positions = []; 

    while (match = pattern.exec(line)) { 
     chords.push(match[1]); 
     positions.push(match.index); 
    } 

    return { 
     "chords" : chords, 
     "positions" : positions 
    }; 
} 

它使用(?:^|\s)以確保弦或者是在該行的開始,或者前面有一個空格,並使用正前瞻(?=$|\s)以確保弦後跟一個空格或位於行尾。添加圓括號以捕捉和絃本身,然後由match[1]訪問。

相關問題