比较使用JavaScript或jQuery的2 div元素内的文本

我有以下2个div标签

<div class="one"> + +++ + </div> 

第二个div标签

 <div class="two"> + + ++++ + ++ + + + + ++ +++ + +++ ++ + +++ + ++ + + ++ + + + + ++ </div> 

现在我想要find如果.one存在于.two 。 如果是的话,我们怎么能在JavaScript中做到这一点?

更新

我想检查+模式。 我的意思是呢

+ +++ +

存在于.two ? 该模式必须以相同的顺序。

@shub的答案似乎并没有工作。 这是JSFiddle的答案。

第1部分:

要查看数据如何匹配,可以尝试将其转换为字母而不是加号。

 <div class="one"> g tuv J </div> <div class="two"> ab cdef g hi jkl m no pqr s tuv wx y zAB C DE FG HI JKLM NO </div> 

你必须做这样的事情:

因为:one.innerText = g \ n tuv \ n J

这将需要变成一个正则expression式,如:/ g | tuv | J / g

要查看交叉匹配,请将第二类的内容复制并粘贴到此网站中,并删除“a”,“m”和“C”之前的空格: http : //regexr.com/3eumc

第2部分

问题是如果“tuv”在string2中移动,它将不会被“J”上方的“u”上方的“g”locking。

为了修正“J”问题之上“u”以上的“g”,我们不得不将这看作游戏棋盘的二维数据集。 这意味着将string转换为matrix(数组数组),其中每个字母加上每个空格被放入数组槽中。 像这样:

 var matrix = [ // 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 = columns. Remember to add +10, +20! [a| |b| | | |c|d|e|f| | |g| |h|i| | |j| |k| |l], // row 0 [m| |n|o| |p|q|r| |s| |t|u|v| |w|x| |y| |z|A|B], // row 1 [C| |D|E| |F| |G| |H|I| |J| |K| |L| |M| |N|O] // row 2 ]; 

现在你可以检查看看是否:

 if ((matrix[0][13] === 'g') && (matrix[1][12] === 't') && (matrix[1][13] === 'u') && (matrix[1][14] === 'v') && (matrix[2][13] === 'J')) { /* SUCCESS when all 5 letters appear & "g" is above "u" & "u" is above "J". The entire cross can move left or right, but lines 1, 2 & 3 can't shift independently of the other 3 lines. Otherwise it should fail. */ } else { // FAIL } 

第3部分…

我已经解决了这个matrixsearch难题。 看到我的jsFiddle在https://jsfiddle.net/briankueck/pern32vv/

这是代码看起来的核心。 打开该jsFiddle链接上的debugging开关,查看它是如何运行的。 🙂

 function getMatrix(cssSelector, canTrim) { // Built by, Clomp! @briankueck http://www.clomp.com var obj = $(cssSelector); if (obj) { var matrix = obj.text() /* Makes sure that we are selecting 3 lines, not 5 * as the example has a \n after <div ...>\n and before \n</div> */ if (canTrim) { matrix = matrix.trim(); } // Now split those 3 lines. matrix = matrix.split(/\n/); /* Trims each array in the matrix. Note: matrix[row] is a string, * but we can treat a string as an array of characters. */ if (canTrim) { // Trims each row, if desired. for (var row = 0; row < matrix.length; row++) { matrix[row] = matrix[row].trim(); } } else { // Gets rid of spaces before matrix 1 in this demo. var maxLength = 0; var space = ' '; // You can also use a period here to see how it works. var tempMatrix = []; for (var row = 0; row < matrix.length; row++) { // This cuts the rows down (vertically) from 5 to 3. if (matrix[row].trim().length > 0) { matrix[row] = matrix[row].replace(/\s/g, space); matrix[row] = matrix[row].replace(/\t/g, space); tempMatrix.push(matrix[row]); if (matrix[row].length > maxLength) { maxLength = matrix[row].length; } } } /* This loops those 3 rows (horizontally) & slices the 1st character off * each array if they are all identical & only contain spaces, which we are * tracking with the period character '.' as dots. */ var charactersToStrip = 0; for (var column = 0; column <= maxLength; column++) { for (var row = 0; row < tempMatrix.length; row++) { if (tempMatrix[row][column] !== space) { break; } else if (row === (tempMatrix.length - 1)) { charactersToStrip++; } } } /* Strips characters, without removing the space before "g" * and the space before "J". */ for (var column = 0; column < charactersToStrip; column++) { for (var row = 0; row < tempMatrix.length; row++) { tempMatrix[row] = tempMatrix[row].substring(1); } } matrix = tempMatrix; } } return matrix; } function matrixSearch(matrixOne, matrixTwo) { // Built by, Clomp! @briankueck http://www.clomp.com var space = ' '; // You can also use a period here to see how it works. // This is for " g". First we trim it, as we only want the "g" character. var searchChar = matrixOne[0].trim(); // Next we find the lock position. var firstCharPosition = matrixTwo[0].indexOf(searchChar); var matchingRows = -1; if (firstCharPosition > -1) { // This should be 1 & not 0. var matchingCharInMatrixOne = matrixOne[0].indexOf(searchChar); // Now we can find the starting index of character 0 in each row of matrixTwo: var startIndex = firstCharPosition - matchingCharInMatrixOne; // This simultaneously scans rows 1, 2 & 3 in both matricies. var matchingRows = 0; for (var row = 0; row < matrixOne.length; row++) { /* We now know both the startIndex = 11 & the lock position = 12. * So let's use them for "tuv" and " J". */ var endIndex = startIndex + matrixOne[row].length; var i = -1; for (var column = startIndex; column < endIndex; column++) { i++; if (matrixOne[row][i] !== space) { var matrixOneCharacter = matrixOne[row][i]; var matrixTwoCharacter = matrixTwo[row][column]; if (matrixOneCharacter !== matrixTwoCharacter) { break; } else if (column === (endIndex - 1)) { // Found it! matchingRows++; } } } } } // Now we can find it: var isFoundInMatrixTwo = ((matchingRows > -1) && (matchingRows === matrixTwo.length)) ? true : false; return isFoundInMatrixTwo; } var cssSelector1 = '.one'; var cssSelector2 = '.two'; var matrixOne = getMatrix(cssSelector1, false); var matrixTwo = getMatrix(cssSelector2, true); var isFound = matrixSearch(matrixOne, matrixTwo); console.log('Is matrix 1 in matrix 2? ', isFound); 

请享用!

顺便说一句,圣诞快乐堆栈溢出社区从克隆!

那么,我们在这里已经有了很好的答案,但是…这是一个更多的方法。 🙂

基本上来说:filterinput,得到干净的模式/matrix(假设开始时会有两个空格 – 必须解决这个问题!),用另一个模式testing它(实际上是将HTML结构和数组从两个=>进行比较)

发生了什么事的视觉表示也在那里。

代码是暴力,可以而且应该清理(​​但它有点作品,哈哈):

 spacer='-'; pattern=$('.one').text().replace(/ /g,spacer).split('\n'); patt=pattern.filter(function(val){ if(val.indexOf('+')>=1) { return val; } }); patt = patt.map(function(x){ return x.slice(2); }); var lgth = 0; var longest; for(var i=0; i < patt.length; i++){ // http://stackoverflow.com/questions/6521245/finding-longest-string-in-array if(patt[i].length > lgth){ var lgth = patt[i].length; longest = patt[i]; } } //console.log(longest.length); longest_sequence=longest.trim().length; matrix=[]; for(j=0;j<patt.length;j++) { // if(patt[j]!=longest) { cleaned=patt[j]+spacer.repeat(longest.length-patt[j].length); cleaned=cleaned.substr(-longest_sequence); } else { cleaned=longest.trim(); } matrix.push(cleaned); } //console.log(matrix.join('\n')); cells=[]; for(i=0;i<matrix.length;i++) { cells.push(matrix[i].split('')); $('table.small').append('<tr>'); } $( "table.small tr" ).each(function( index ) { for(j=0;j<cells[index].length;j++) { $(this).append('<td>'+cells[index][j]+'</td>'); } }); data=$('.two').text().replace(/ /g,spacer).split('\n'); data=data.filter(function(val){ if(val.indexOf('+')>=1) { return val; } }); data = data.map(function(x){ return x.slice(2); }); //console.log(data); //console.log(data.join('\n')); cells=[]; for(i=0;i<data.length;i++) { cells.push(data[i].split('')); $('table.big').append('<tr>'); } $( "table.big tr" ).each(function( index ) { for(j=0;j<cells[index].length;j++) { $(this).append('<td>'+cells[index][j]+'</td>'); } }); //comparing!!! pattern_arr=[]; $("table.small tr").each(function() { pattern_arr.push($(this).children().text().trim()) }); function arraysEqual(a1,a2) { /* WARNING: arrays must not contain {objects} or behavior may be undefined */ // console.log(JSON.stringify(a1)+':'+JSON.stringify(a2)); // console.log('________________________________________'); return JSON.stringify(a1)==JSON.stringify(a2); } count=-1; timer=setInterval(function(){ count++; sliced_arr=[]; slices=[]; $( "table.big tr" ).each(function( index ) { $(this).children('td').removeClass('search'); sliced=$(this).children('td').slice( count,count+longest_sequence ); slices.push(sliced); $(sliced).addClass('search'); sliced_arr.push($(sliced).text().trim()); if(arraysEqual(pattern_arr,sliced_arr)) { //$(sliced).addClass('found').removeClass('search'); $.each( slices, function( key, value ) { $(this).addClass('found').removeClass('search'); }); //$(slices).addClass('found').removeClass('search'); $('#status').text('Found!'); clearInterval(timer); } for(i=0;i<sliced_arr.length;i++) if(sliced_arr[i]=="") { clearInterval(timer); $('#status').text('Not found!'); break; } }); }, 1000); 
 .one, .two { font-size:22px; } table.big { border:1px solid #666; padding:0; border-collapse:collapse; } table.big td { border:1px solid #666; padding:5px; margin:0; } table.small { border:1px solid red; padding:0; border-collapse:collapse; } table.small td { border:1px solid red; padding:5px; margin:0; } .found { font-weight:bold; color:white; background:green; } .search { font-weight:bold; color:white; background:orange; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="one"><pre> + +++ + </pre></div> <table class="small"> </table> <div class="two"><pre> + + ++++ + ++ + + + + ++ +++ + +++ ++ + +++ + ++ + + ++ + + + + ++ </pre></div> <table class="big"> </table> <div id="status"> </div> 

@ 2619 之前的post显示了对于Bliffoscope问题的兴趣。 鉴于div.onediv.two中的文本内容(以固定宽度字体ascii艺术风格)是从+ (它们表示活动像素)和“ “(空间) 处于非活动状态 ,我们的想法是find我们可以将div.one放在div.two哪个位置,这样两个模式就形成了更多的交集,我只考虑两个活动像素的交点给定的图像。

在这个例子中, +o代替以突出显示每个匹配的交集。 使用canvas简化版本可以在这里find。

在下面的SO片段和JSFiddle演示中 ,单击“ Next和“ Previous链接,或者按下键盘上的箭头button,浏览匹配项。

_main.best_positions()返回每个可能叠加的交集的数量,以任何程度的错误容忍度(按照交集的数量sorting)(首先有更多匹配)。

 var PatternFinder; PatternFinder = (function(win, doc, undefined) { 'use strict'; var _main = { selectors: { object_1_pattern: ".one", background_pattern: ".two", results: ".three", next_button: ".next", previous_button: ".previous", match_score: ".intersecting_coords", match_nr: ".match_nr", }, cache: { object_text_string: '', context_text_string: '' }, init: function() { _main.cache.object_text_string = $(_main.selectors.object_1_pattern).text(); _main.cache.context_text_string = $(_main.selectors.background_pattern).text(); // Parse our images from the text strings. _main.serialized_context = _main.serialize_map(_main.cache.context_text_string); _main.serialized_object = _main.serialize_map(_main.cache.object_text_string); // Find the position of the object with larger amount of intersecting coordinates _main.best_positions = _main.get_best_position(_main.serialized_context, _main.serialized_object); _main.current_result = _main.best_positions.length - 1; // Draw initial results _main.print_output(_main.current_result); // Handle user input $(_main.selectors.next_button).click(function() { _main.current_result -= 1; _main.print_output(); }); $(_main.selectors.previous_button).click(function() { _main.current_result += 1; _main.print_output(); }); // Keyboard: Arrow keys $(document).keydown(function(e) { switch (e.which) { case 37: { // left _main.current_result += 1; _main.print_output(); break; } case 39: { // right _main.current_result -= 1; _main.print_output(); break; } default: return; } e.preventDefault(); // prevent the default action (scroll / move caret) }); }, // Highlight an intersection. // Replace "+" by "o" in coords _x, _y. highlight_match: function(_x, _y, background) { var x = 0, y = 0, i = 0, output = "", c; for (i = 0; i < background.length; i += 1) { c = background[i]; if (c == "+" && x == _x && y == _y) { output = output + "o"; } else { output = output + c; } x += 1; if (c == "\n") { x = 0; y += 1; } } return output; }, // Receive the translated serialized object, // and the original text string for the background. // Return the background text string, with the matches // between it and serialized_object highlighted. merge_and_deserialize: function(serialized_object, background) { var i; for (i = serialized_object.length - 1; i >= 0; i--) { background = _main.highlight_match(serialized_object[i][0], serialized_object[i][1], background); } return background; }, // Receive a text string like the one from the Stack Overflow ticket, // return an array of coordinates of filled in pixels (+ or space). serialize_map: function(char_map) { var x = 0, y = 0, c, i, map = []; for (i = 0; i < char_map.length; i += 1) { c = char_map[i]; if (c == "+") { map.push([x, y]); } x += 1; if (c == "\n") { x = 0; y += 1; } } return map; }, // Find number of intersections between two images (that's where the magic happens). // Found here: https://gist.github.com/lovasoa/3361645 array_intersect: function() { var a, d, b, e, h = [], l = [], f = {}, g; g = arguments.length - 1; b = arguments[0].length; for (a = d = 0; a <= g; a += 1) { e = arguments[a].length, e < b && (d = a, b = e); } for (a = 0; a <= g; a += 1) { e = a === d ? 0 : a || d; b = arguments[e].length; for (l = 0; l < b; l += 1) { var k = arguments[e][l]; f[k] === a - 1 ? a === g ? (h.push(k), f[k] = 0) : f[k] = a : 0 === a && (f[k] = 0); } } return h; }, // Translate the coordinates of a serialized image. translate: function(coords, ix, iy) { return [coords[0] + ix, coords[1] + iy]; }, // Find in which position the object has more intersections with the background. get_best_position: function(context, object) { // Calculate image dimensions var context_width = context.sort(function(a, b) { return b[0] - a[0]; })[0][0], context_height = context.sort(function(a, b) { return b[1] - a[1]; })[0][1], object_width = object.sort(function(a, b) { return b[0] - a[0]; })[0][0], object_height = object.sort(function(a, b) { return b[1] - a[1]; })[0][1]; // Swipe context, store amount of matches for each patch position. var similaritudes = [], cx, cy, intersection, translated_object; for (cx = -object_width; cx < context_width; cx += 1) { for (cy = -object_height; cy < context_height; cy += 1) { translated_object = object.map(function(coords) { return _main.translate(coords, cx, cy); }); intersection = _main.array_intersect(context, translated_object); if (intersection.length > 0) { similaritudes.push({ coords: [cx, cy], similaritudes: intersection.length }); } } } // Return coords, // sorted by those for which number of matches was greater. return similaritudes.sort(function(a, b) { return a.similaritudes - b.similaritudes; }); }, print_output: function() { var positioned_object; // Get the coordinates of one of our matches. _main.current_result = Math.max(_main.current_result, 1); _main.current_result = Math.min(_main.current_result, _main.best_positions.length - 1); var score = _main.best_positions.slice(_main.current_result)[0].similaritudes; var best_position = _main.best_positions.slice(_main.current_result)[0].coords; // Translate our image patch to the position defined by _main.current_result. positioned_object = _main.serialized_object.map(function(coords) { return _main.translate(coords, best_position[0], best_position[1]); }); // Produce merged images (background after replace). var final_image = _main.merge_and_deserialize(positioned_object, _main.cache.context_text_string); // Print image and information $(_main.selectors.results).text(final_image); $(_main.selectors.match_score).text(score); $(_main.selectors.match_nr).text(_main.best_positions.length - _main.current_result); } }; // Expose methods _main.public_methods = { init: _main.init, }; return _main.public_methods; }(window, document)); PatternFinder.init(); 
 .one, .two { display: none; } .three { white-space: pre; font-family: "Lucida Console", Monaco, "Courier New", Courier, monospace; margin: 0 0 20px 0; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="one"> + +++ + </div> <div class="two"> + + ++++ + ++ + + + + ++ +++ + +++ ++ + +++ + ++ + + ++ + + + + ++ </div> <h3>Match: <span class="match_nr"></span></h3> <h5>Intersecting coordinates: <span class="intersecting_coords"></span></h5> <div class="three"></div> <nav> <a class="previous" href="#">Previous</a> <a class="next" href="#">Next</a> </nav> <p><sub>Click Next and Previous or use the keyboard arrows to see other possible matches.</sub></p> 

下面的代码片段查找在“two”div中的“one”模式的所有出现,如标记中所写的那样。 结果在控制台输出中报告(行索引和行中的位置)。

积分:

  1. Clomp的评论帮助我理解这个问题是关于标记模式的
  2. Tim Down从这个答案中借用了getIndicesOf
 function find() { var i, j, k; var txtOne = $('.one').text(); var txtTwo = $('.two').text(); var linesOne = txtOne.split("\n"); // Get search patterns from "one" var patterns = getSearchPatterns(linesOne); // Get content lines from "two" var linesTwo = txtTwo.split("\n"); while (linesTwo.length > 0 && !linesTwo[0]) { linesTwo.shift(); } // Get all the positions of all patterns in all lines var searchResults = []; var patternInLines, positionsInLine; for (i = 0; i < patterns.length; i++) { patternInLines = []; for (j = 0; j < linesTwo.length; j++) { positionsInLine = getIndicesOf(patterns[i], linesTwo[j], true); patternInLines.push(positionsInLine); } searchResults.push(patternInLines); } // Get the occurrences of all patterns at the same position on consecutive lines var results = []; var firstPatternInLine, firstPatternPosition, patternInLine, found; var firstPattern = searchResults[0]; for (j = 0; j < linesTwo.length - patterns.length; j++) { firstPatternInLine = firstPattern[j]; for (k = 0; k < firstPatternInLine.length; k++) { firstPatternPosition = firstPatternInLine[k]; found = true; for (i = 1; i < patterns.length; i++) { patternInLine = searchResults[i][j + i]; if (patternInLine.indexOf(firstPatternPosition) < 0) { found = false; break; } } if (found) { results.push({ line: j, position: firstPatternPosition }) } } } // Display results for (i = 0; i < results.length; i++) { console.log(results[i]); } if (results.length < 1) { console.log("No occurrence found"); } } // Trim the search lines to get the minimal search "block" function getSearchPatterns(lines) { var items = []; var result = []; var i, txt, offset, item; var minOffset = 1000000; var maxLength = 0; for (i = 0; i < lines.length; i++) { txt = lines[i].trim(); if (txt) { offset = lines[i].indexOf(txt); items.push({ str: txt, offset: offset }); minOffset = Math.min(offset, minOffset); } } for (i = 0; i < items.length; i++) { item = items[i]; item.offset -= minOffset; maxLength = Math.max(item.offset + item.str.length, maxLength); } for (i = 0; i < items.length; i++) { item = items[i]; result.push(paddRight(paddLeft(item.str, item.offset), maxLength)); } return result; } function paddLeft(str, count) { var padding = ""; for (var i = 0; i < count; i++) { padding += " "; } return padding + str; } function paddRight(str, length) { var result = str; while (result.length < length) { result += " "; } return result; } // Find all positions of search string in string // By Tim Down at https://stackoverflow.com/a/3410557/1009922 function getIndicesOf(searchStr, str, caseSensitive) { var searchStrLen = searchStr.length; if (searchStrLen == 0) { return []; } var startIndex = 0, index, indices = []; if (!caseSensitive) { str = str.toLowerCase(); searchStr = searchStr.toLowerCase(); } while ((index = str.indexOf(searchStr, startIndex)) >= 0) { indices.push(index); startIndex = index + searchStrLen; } return indices; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="one"> a bcd e </div> <div class="two"> ++ + ++ ++++ + ++ + + + a + + ++++ a ++ + + +bcd + a +++ + bcd ++ + +++ e +bcd + + ++ e + + + ++ ++ + e ++++++++++++++++++++++ </div> <button onclick="find()">Test!</button> 

你的jQuery代码将看起来像这样。 你可以用这个逻辑玩更多的东西

  jQuery().ready(function(){ var lines = $(".two").text().split("\n"); for(i=1;i<=lines[1].length;i++){ if(lines[1][i]=='+' && lines[2][i-1]!='undefined' && lines[1][i]==lines[2][i-1] && lines[2][i]!='undefined' && lines[1][i]==lines[2][i] && lines[2][i+1]!='undefined' && lines[1][i]==lines[2][i+1] && lines[3][i]!='undefined' && lines[1][i]==lines[3][i] ){ console.log('exists'); } } }); 

这是小提琴: https : //jsfiddle.net/ahmadasjad/12eqhs7L/5/

在以前的文章中有相当有趣的想法,我喜欢增加function更紧凑的方法(它使用lodash)。 主要思想是修剪匹配的文本,并与目标文本上的切换窗口( 剪切 )进行比较。 在该函数之上还返回从左边find匹配的位置。 请参阅工作小提琴 :

 function findText(text, search) { const width = maxWidth(search)-minTrim(search); const matcher = cut(search, minTrim(search),width).join(''); return _.range(text[1].length) // create array of possible matches .map(col=>cut(text, col, width).join('')) .indexOf(matcher)+1; // and match with matcher } // Returns left padding size, eg 3 in the example function minTrim(t) { return _.min(t.filter(s=>!!s).map(s=>s.length-_.trimStart(s).length)) } // Returns window within $text at $start position with $width function cut(text, start, width) { return text.map(s=>_.padEnd(s.substr(start,width),width)) } // Returns maximum width of the line within text function maxWidth(text) { return _.max(text.map(s=>s.length)) } 

函数findText可以像这样使用:

 const two=document.getElementsByClassName("two")[0].innerHTML.split('\n'); const one=document.getElementsByClassName("one")[0].innerHTML.split('\n'); alert((pos=findText(two,one)) ? `found at position ${pos}` : "not found"); 

选项2如果string只包含'+'且长度不超过64个字符,我们可以将上面的函数转换成位掩码匹配。 例如,将每个string转换为二进制数字,然后移动目标string,应用search掩码(例如上例中的窗口)并比较数字。 看到工作小提琴 :

 function findTextBin(text,search) { const toBin=str=>str.split('') .reduce((res,c)=>res<<1|(c==='+'?1:0),0) let one=search.map(toBin) let mask=toBin(_.max(one).toString(2).split('').map(c=>'+').join('')) let two=text.map(toBin) let length=_.max(text.map(str=>str.length)) for(let i=length; i; i--,two=two.map(num=>num>>1)) if(two.every((num,row)=>(num&mask)===one[row])) return i-mask.toString(2).length; return false; } 

只是一个build议,但你可以散列的内容来比较它们。 此代码使用CryptoJS库生成MD5哈希

 <script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/md5.js"></script> <script> var div1 = CryptoJS.MD5( $('.one').text() ); var div2 = CryptoJS.MD5( $('.two').text() ); if(div1 === div2) { // your code here } </script> 

假设两行中的行数相同,下面的解决scheme可以简化查找模式。

前提条件:

这个解决scheme需要这个模式,而且要形成的目标如下:

 var pattern = [ ' + ', '+++', ' + ' ]; var target = [ '+ + ++++ + ++ + + +', '+ ++ +++ + +++ ++ + +++', '+ ++ + + ++ + + + + ++ ' ]; 

我认为一个简单的JavaScript操作可以做到这一点 – 逐行阅读HTML,并将其附加到数组。 如果需要,我也可以提供该代码。

怎么运行的:

代码首先决定pattern的宽度,然后继续在target数组中find这种宽度逐列的模式。 当检测到较低宽度的图案或find匹配时,循环停止。

代码:

 // Our core function function matches(target, pattern) { if (pattern.length > target.length) { return false; } var patternWidth = findPatternWidth(pattern); var startIndex = 0; var currentPattern = getNextPattern(target, startIndex, patternWidth); while (patternValid(currentPattern, patternWidth)) { if (identicalArrays(currentPattern, pattern)) { return true; } startIndex++; currentPattern = getNextPattern(target, startIndex, patternWidth); } return false; } // -*-*-*-*-*- HELPER FUNCTIONS -*-*-*-*-*-* // Finds the width of the pattern we want to match function findPatternWidth(pattern) { var maxWidth = 0; for (var i = 0; i < pattern.length; i++) { if (pattern[i].length > maxWidth) { maxWidth = pattern[i].length; } } return maxWidth; } // Finds the next suitable pattern, starting with an index, of a maximum width function getNextPattern(target, startIndex, maxWidth) { var result = []; for (var i = 0; i < target.length; i++) { result.push(target[i].substr(startIndex, maxWidth)); } return result; } // Checks if two non-nested arrays are identical function identicalArrays(source, target) { if (source.length !== target.length) { return false; } for (var i = 0; i < source.length; i++) { if (source[i] !== target[i]) { return false; } } return true; } // Checks if a given pattern is of given width function patternValid(pattern, maxWidth) { for (var i = 0; i < pattern.length; i++) { if (pattern[i].length < maxWidth) { return false; } } return true; } 

我相信这种方法可以扩展到摆脱这种假设the number of rows are same in both

要find另一个string中的模式,首先find相互之间的相对位置。 然后检查第二个string中的加号是否处于相同的相对位置。

findCoordinates函数查找模式中相对于模式string中第一个加号的位置。 对于这个模式,

  + +++ + 

最上面的+在(0,0)。 第二行中的第一个+在(-1,1)处,因为它在第一个+下面一行和第一个的左边。 类似地,其他的脉冲分别位于(0,1),(1,1)和(0,2)。

hasPattern函数使用相对坐标来检查模式是否出现在第二个string中。 对于第二个string中的每个+ ,它会检查相应位置是否有其他+字符与该模式相匹配。 对于示例模式,函数将检查一个字符是否是一个加号。 如果是+ ,则检查左下方,右下方,右下方和下方两行中的字符。 如果这些字符也是加号,那么函数返回true。

 function findCoordinates(string) { var rows = string.split('\n'); var coordinates = []; var first = null; for (var i = 0; i < rows.length; i++) { for (var j = 0; j < rows[i].length; j++) { if (rows[i][j] === '+') { if (first === null) { first = {x:j, y:i}; } coordinates.push({x:j-first.x, y:i-first.y}); } } } return coordinates; } function hasPattern(string, coordinates) { var rows = string.split('\n'); var matches = 0; var coordinate = null; for (var i = 0; i < rows.length; i++) { for (var j = 0; j < rows[i].length; j++) { if (rows[i][j] === '+') { matches = 0; for (var k = 0; k < coordinates.length; k++) { coordinate = coordinates[k]; if (rows[i + coordinate.y] && rows[i + coordinate.y][j + coordinate.x] === '+') { matches++; } } if (matches === coordinates.length) { return true; } } } } return false; } var one = document.querySelector('.one'); var two = document.querySelector('.two'); console.log(hasPattern(two.textContent, findCoordinates(one.textContent))); 
 div { font-family: monospace; white-space: pre; } 
 <div class="one"> + +++ + </div> <div class="two"> + + ++++ + ++ + + + + ++ +++ + +++ ++ + +++ + ++ + + ++ + + + + ++ </div> 
 $('.one').diffString($('.two').html()); 

如果test patternsource pattern的行数不同,则此解决scheme将不起作用。

这个想法是创build一个模式的连续列的string。 然后,我们可以使用indexOf轻松检查模式是否存在

例如,一个这样的模式:

 1 2 3 + + + + + + 

变成"+ + +++ +"; // equivalent of ["+ +"," ++","+ +"].join(""); "+ + +++ +"; // equivalent of ["+ +"," ++","+ +"].join("");

在这里输入图像说明 这里是小提琴https://jsfiddle.net/flyinggambit/vcav3c46/

 function getVerticalPattern(pattern){ // split the pattern in to an array, each item represents each line var pattern = pattern.split("\n"); var numLines = pattern.length; // Find the number of lines // Find the longest string var longestString = 0; for(var i=0; i<pattern.length; ++i){ longestString = pattern[i].length; } // Rearrange the pattern var newPattern = []; for (var i=0; i<longestString; i++){ for (var j=0; j<numLines; j++){ if(pattern[j] && pattern[j].length){ // sometimes the split was creating empty strings "" newPattern.push(pattern[j][i]); } } } return newPattern.join(""); } function findPattern(testPattern, srcPattern){ return (getVerticalPattern(srcPattern)).indexOf(getVerticalPattern(testPattern)); } var srcPattern = document.getElementsByClassName("two")[0].innerHTML; var testPattern = document.getElementsByClassName("one")[0].innerHTML; var result = findPattern(testPattern, srcPattern); if(result !== -1){ console.log("pattern found"); }else{ console.log("pattern not found"); } 
 <pre class="one"> + +++ + </pre> <pre class="two"> + + ++++ + ++ + + + + ++ +++ + +++ ++ + +++ + ++ + + ++ + + + + ++ </pre> 

这是快速和丑陋的,仍然有一些错误检查和优化尚待完成…但足以显示的概念:

 var pattern = [ '+ + ', '+ ++', '+ ++' ]; var target = [ '+ + ++++ + ++ + + +', '+ ++ +++ + +++ ++ + +++', '+ ++ + + ++ + + + + ++ ' ]; function getAllIndexes(arr, val) { var indexes = [], i = -1; while ((i = arr.indexOf(val, i+1)) != -1){ indexes.push(i); } return indexes; } function checkNextRow(pattern, target, pRow, tRow) { var matchePos = target[i].indexOf(pattern[0]); } function test(pattern, target) { //get pattern hights for later var pH = pattern.length; var tH = target.length; //target should have equal or more rows if (tH < pH) return 'not found'; //which is the lowest row of the target where top row of the pattern can be matched? tLastTop = tH - pH; //function to check row of pattern function checkRest(pRow, tRow, hPosMatch) { console.log('searching for '+pattern[pRow]+' in '+target[tRow]); var matchPos = target[tRow].indexOf(pattern[pRow], hPosMatch); console.log('search result>>>>'+matchPos); if (matchPos >= 0 && matchPos === hPosMatch) { if (pRow === pH-1) { console.log('last row of pattern matched'); return true; //last row of pattern matched } else { console.log('calling checkRow from itself'); return checkRest(pRow+1, tRow+1, hPosMatch); } } else { console.log('pattern not found in row, returning false',hPosMatch, matchPos); return false; } } //search for top row of pattern for (i = 0; i <= tLastTop; i++) { //get all accurance indexes of patern's first row var matches = getAllIndexes(target[i], pattern[0]); console.log("matches",matches); if (matches.length <= 0) continue; //try other rows for each accurance position for (h = 0; h <= matches.length; h++) { var hPosMatch = matches[h]; console.log('calling checkRow from iterator'); var result = checkRest(1,i+1,hPosMatch); if (result) return true; } } return false; } console.log(test(pattern, target)); 

I skipped loading DIV content into pattern/target vars as it seems trivial. Also I assumed spaces are also important for pattern, meaning ' + + ' does not match ' +++ '

JSBin is here: http://jsbin.com/kayeyi/edit?js,console

To not overcomplicate things I made some assumptions on the inputs:

  1. Number of lines in inputs are equal
  2. Any empty line from inputs can be omitted
  3. Every non-empty line of inputs should contain whitespace characters at "missing" places
  4. The whitespace character in both inputs is the same and it's NOT a line break

Besides of collecting data from the DOM the solution goes through following steps:

  1. Both pattern and input are converted into arrays of strings, each string for a line. Arrays must have same length ( assumption 1 )
  2. For each pair of lines list of possible matches are collected – list of all indices in input string on which pattern string is included
  3. Result lists are flattened into single list and all indices are counted. Now for each possible index we have number of lines where match is successful
  4. Filter the result to leave only indices with maximum count

There is also a working fiddle of the solution

 function indexOf(pattern, input){ if(pattern.length !== input.length) throw 'Works only for same number of lines'; var counts = [].concat(...input.map((s,i) => allMatches(pattern[i],s))).reduce((r,e) => (r[e] = (r[e] || 0) + 1, r), {}); //find all matches for all lines and flatten the result var stops = Object.keys(counts).filter(k => counts[k] === pattern.length); //get only those that span across all the lines return stops[0] || -1; //first found or -1 if empty } function allMatches(substr, str){ var result = [], index = 0; while(~(index = str.indexOf(substr, index))) // ~(-1) is falsy result.push(index++); return result; } function readContent(element){ return (element.value || element.textContent).split(/[\r\n]+/).filter(s => s.length); //get all non-empty lines } function showResult(pattern, input){ var chars = Array(input[0].length).fill('\xa0'); // &nbsp; chars[indexOf(pattern, input)] = '^'; document.querySelector('.result').textContent = chars.join(''); } function updater(){ showResult( readContent(document.querySelector('.one')), readContent(document.querySelector('.two')) ); } document.querySelector('.one').addEventListener('input', updater); document.querySelector('.two').addEventListener('input', updater); updater(); 
 .one, .two, .result{ padding: 0; margin: 0; font-family: monospace; width: 100%; font-size: 1rem; } 
 <textarea class="one" rows="4"> + +++ + </textarea> <textarea class="two" rows="4"> + + ++++ + ++ + + + + ++ +++ + +++ ++ + +++ + ++ + + ++ + + + + ++ </textarea> <div class="result"></div>