我們的項目上有一個這樣的場景:一個下拉選擇框,同時要支持用戶輸入,將最終的結果顯示在文本框中(就是普通的字元串,用戶在下拉框中選擇的放在【】中)……不知道能不能想象出來,寫上一篇筆記的時候發現和咱們博客園選擇“tag 標簽”的功能有點接近啊,我們的ui還是跟她有些不同。 還是拿一個具體的例子說一下吧 ...
我們的項目上有一個這樣的場景:一個下拉選擇框,同時要支持用戶輸入,將最終的結果顯示在文本框中(就是普通的字元串,用戶在下拉框中選擇的放在【】中)……不知道能不能想象出來,寫上一篇筆記的時候發現和咱們博客園選擇“tag 標簽”的功能有點接近啊,我們的ui還是跟她有些不同。
還是拿一個具體的例子說一下吧。下拉框中有“姓名”、“年齡”兩個選擇項,你可以選擇也可以自己在文本框中輸入,例如文本框中的內容是:自定義001【姓名】自定義002【年齡】自定義003。我們要做的就是解析這個字元串,我們需要識別出其中的“姓名”和“年齡”(無論是用戶選擇的,還是用戶輸入的),最後的結果應該是這樣的 ["自定義001","【姓名】","自定義002","【年齡】","自定義003"]。
這裡還要在補充一點他們的要求:就是可以同時匹配多個時候(開始的索引位置相同,但是結尾不同),我們需要識別下拉列表中的第一個。有點抽象,還是說一個例子吧。這裡下拉列表中有“姓名】”和“姓名”兩個,這時候文本框中的內容是:自定義001【姓名】】自定義002。交換下拉列表中的順序,最終得到的結果是不一樣的。
說了這麼一大推,感覺好沒意思啊!其實還是蠻有意思的(解析這個)。遇到這個問題之後最先想到的就是,遍歷下拉框數組,利用indexOf查找看看有沒有,之後截取三部分(前面的、自己、後面的),之後遞歸處理前面和後面的部分。我去,想著簡單但是寫的時候好費勁啊!最後查了一下,看看有沒有這種方法,在目標字元串中找出指定的N個字元串的所在起始位置,一個方法可以搞定的那種,最後還是正則表達式救了我。現在我可以得到下拉選項中的每一項在目標字元串的起始位置了,剩下的就是利用這些起始位置去截取目標字元串了,腦袋一熱將這些這些索引位置放到一個數組中(去重),之後排序,之後兩兩已截取不就完了,這樣寫完之後就真的涼涼了,很多字元串都解析錯誤,之後弄了好幾版都不行,決定靜下來分析一下,看看到底有多少種情況。之前竟然還想到數據去重(確實是第一次寫就去重了),但是就沒有想想什麼情況下有重覆的情況出現:索引開始相同,某一個的索引結束是另一個的開始……後來我直接畫圖了,列出了12中情況,在下麵可以在紙上畫,這裡呢?我也又找到了一個神器:圖形計算器,你看一下:
一共有12中情況,要是一個一個if else 太費勁了,細看一下發現中間的8種情況是有問題的,如果將這8種情況下的起始索引都放到數組中去截取字串,那麼他就會將下拉框中的下拉項(也就是圖中兩個中的一個截斷),所以呢用了一下排除法。之後呢,為了驗證我也列舉了上面的6中情況(下麵分別給出例子),感覺前面的6個和後面的6個是對稱的……
// 參考: // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@matchAll // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll // 待選列表(下拉列表項) var toBeSelectedList = [{ dispalyName: "姓名", dispalyIndex: "name1" }, { dispalyName: "年齡", dispalyIndex: "age" }, { dispalyName: "姓【名", dispalyIndex: "name2" }, { dispalyName: "名】001", dispalyIndex: "name3" }, { dispalyName: "【姓名", dispalyIndex: "name4" }, { dispalyName: "1【姓名】1", dispalyIndex: "name5" }, { dispalyName: "姓名】", dispalyIndex: "name6" } ]; var tempDispalyNameArr = toBeSelectedList.map(function (item) { return item.dispalyName; }); // 解析方法 var getTargetArrByUserInputAndFilterStrs = function (userInputStr, filterStrs) { var tempIndexPosArr = [], tempIndexPosObjArr = [], tempFilterStrAddCharObj = {}; filterStrs.forEach(function (filterStr, index) { var tempKey = '【' + filterStr + '】', tempRegexp = new RegExp(tempKey, 'g'), match; tempFilterStrAddCharObj[tempKey] = filterStr; while ((match = tempRegexp.exec(userInputStr)) !== null) { var tempFilterPosArrs = tempIndexPosObjArr.filter(function (startAndLastIndexItem) { // return (match.index >= startAndLastIndexItem.index && match.index < startAndLastIndexItem.lastIndex) || // (match.index < startAndLastIndexItem.index && tempRegexp.lastIndex >= startAndLastIndexItem.lastIndex); return !(tempRegexp.lastIndex <= startAndLastIndexItem.index || match.index >= startAndLastIndexItem.lastIndex); }); if (tempFilterPosArrs.length === 0) { tempIndexPosObjArr.push({ index: match.index, lastIndex: tempRegexp.lastIndex }); } } }); tempIndexPosObjArr.forEach(function (indexObj) { if (tempIndexPosArr.indexOf(indexObj.index) < 0) { tempIndexPosArr.push(indexObj.index); } if (tempIndexPosArr.indexOf(indexObj.lastIndex) < 0) { tempIndexPosArr.push(indexObj.lastIndex); } }); if (tempIndexPosArr.indexOf(0) < 0) { tempIndexPosArr.push(0); } if (tempIndexPosArr.indexOf(userInputStr.length) < 0) { tempIndexPosArr.push(userInputStr.length); } tempIndexPosArr = tempIndexPosArr.sort(function (a, b) { return a - b; }); var lastNeedArr = []; tempIndexPosArr.forEach(function (posIndex, index) { if (index < tempIndexPosArr.length - 1) { var tempIsOneFilterStr = userInputStr.substring(posIndex, tempIndexPosArr[index + 1]); // if(tempFilterStrAddCharObj.hasOwnProperty(tempIsOneFilterStr)){ // tempIsOneFilterStr=tempFilterStrAddCharObj[tempIsOneFilterStr] // } lastNeedArr.push(tempIsOneFilterStr); } }); return lastNeedArr; }; // 等待解析的字元串(也就是用戶選擇或者輸入的最終結果) var waitAnalysisStr1 = "自定義001【姓名】自定義002【年齡】自定義003"; var toBeSelectedList1_1 = ["姓名", "年齡"]; // ["自定義001","【姓名】","自定義002","【年齡】","自定義003"] var toBeSelectedList1_2 = ["年齡", "姓名"]; // ["自定義001","【姓名】","自定義002","【年齡】","自定義003"] var waitAnalysisStr2 = "自定義001【姓名】【年齡】自定義002"; var toBeSelectedList2_1 = ["姓名", "年齡"]; // ["自定義001","【姓名】","【年齡】","自定義002"] var toBeSelectedList2_2 = ["年齡", "姓名"]; // ["自定義001","【姓名】","【年齡】","自定義002"] var waitAnalysisStr3 = "自定義001【姓【名】001】自定義002"; var toBeSelectedList3_1 = ["姓【名", "名】001"]; // ["自定義001","【姓【名】","001】自定義002"] var toBeSelectedList3_2 = ["名】001", "姓【名"]; // ["自定義001【姓","【名】001】","自定義002"] var waitAnalysisStr4 = "自定義001【【姓名】自定義002"; // 【姓名 、 姓名 交換順序試試 var toBeSelectedList4_1 = ["【姓名", "姓名"]; // ["自定義001","【【姓名】","自定義002"] var toBeSelectedList4_2 = ["姓名", "【姓名"]; // ["自定義001【","【姓名】","自定義002"] var waitAnalysisStr5 = "自定義001【1【姓名】1】自定義002"; // 1【姓名】1 、 姓名 交換順序試試 var toBeSelectedList5_1 = ["1【姓名】1", "姓名"]; // ["自定義001","【1【姓名】1】","自定義002"] var toBeSelectedList5_2 = ["姓名", "1【姓名】1"]; // ["自定義001【1","【姓名】","1】自定義002"] var waitAnalysisStr6 = "自定義001【姓名】】自定義002"; // 姓名 、 姓名】 交換順序試試 var toBeSelectedList6_1 = ["姓名】", "姓名"]; // ["自定義001","【姓名】】","自定義002"] var toBeSelectedList6_2 = ["姓名", "姓名】"]; // ["自定義001","【姓名】","】自定義002"] var tempTargetArr1_1 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr1, toBeSelectedList1_1); console.log(JSON.stringify(tempTargetArr1_1)); var tempTargetArr1_2 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr1, toBeSelectedList1_2); console.log(JSON.stringify(tempTargetArr1_2)); var tempTargetArr2_1 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr2, toBeSelectedList2_1); console.log(JSON.stringify(tempTargetArr2_1)); var tempTargetArr2_2 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr2, toBeSelectedList2_2); console.log(JSON.stringify(tempTargetArr2_2)); var tempTargetArr3_1 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr3, toBeSelectedList3_1); console.log(JSON.stringify(tempTargetArr3_1)); var tempTargetArr3_2 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr3, toBeSelectedList3_2); console.log(JSON.stringify(tempTargetArr3_2)); var tempTargetArr4_1 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr4, toBeSelectedList4_1); console.log(JSON.stringify(tempTargetArr4_1)); var tempTargetArr4_2 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr4, toBeSelectedList4_2); console.log(JSON.stringify(tempTargetArr4_2)); var tempTargetArr5_1 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr5, toBeSelectedList5_1); console.log(JSON.stringify(tempTargetArr5_1)); var tempTargetArr5_2 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr5, toBeSelectedList5_2); console.log(JSON.stringify(tempTargetArr5_2)); var tempTargetArr6_1 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr6, toBeSelectedList6_1); console.log(JSON.stringify(tempTargetArr6_1)); var tempTargetArr6_2 = getTargetArrByUserInputAndFilterStrs(waitAnalysisStr6, toBeSelectedList6_2); console.log(JSON.stringify(tempTargetArr6_2));測試代碼
其實到現在,都不知道現在的演算法是不是包住了所有情況,雖然下麵的例子都測試通過了,還是等著真正的測試人員去測試吧!如果哪位大神有更好的方法請賜教,謝謝!