दिलचस्प पोस्ट
एक विशेष टैग को क्लोन कैसे करें मृदुरीय रिपॉजिटरी के साथ गिट इंटरऑपरेबिलिटी मेस्ड क्लास जिसे डिफॉल्ट कन्स्ट्रक्टर के साथ बुलाया गया, ओपनसीएल सी ++ काम नहीं कर रहा है WCF के साथ "आवेदन / एक्स-www-फॉर्म-यूआरएलएन्कोडेड" डेटा का समर्थन करने का सर्वोत्तम तरीका? Django admin इनलाइन के अंदर देश / राज्य / शहर लटकती मेनू आपको एक स्टैटिक क्लास के बजाय सिंगलटन पैटर्न का उपयोग कब करना चाहिए? चर के साथ अभिव्यक्ति के लिए grep Devise के सत्र नियंत्रक के लिए एक before_filter को कैसे छोड़ें? JSP / Servlet की छिपी हुई विशेषताओं Django स्टार्टअप कोड कहां लगाया जाए? Laravel सेटअप स्ट्रीम को खोलने में विफल रहा मैं दो सरणियों में मिलान वाले मान कैसे पा सकता हूं? मैं asp.net mvc अनुप्रयोग में एक नियंत्रक कार्रवाई के लिए अनुरोध समयबाह्य कैसे निर्धारित कर सकता हूँ क्या कोई भी सरल जावा वेब-ऐप फ्रेमवर्क सुझा सकता है? डिवी के अंदर की सीमा रखते हुए और इसके किनारे पर नहीं

कैसे जावास्क्रिप्ट के साथ एक नोड में किसी पाठ का भाग लपेटें

मुझे हल करने के लिए एक चुनौतीपूर्ण समस्या है मैं एक स्क्रिप्ट पर काम कर रहा हूं जो एक इनपुट के रूप में एक regex लेता है। तब यह स्क्रिप्ट दस्तावेज़ में इस regex के लिए सभी मैचों को खोजता है और प्रत्येक मैच अपने स्वयं के <span> तत्व में लपेटता है। कठिन हिस्सा यह है कि पाठ एक स्वरूपित HTML दस्तावेज़ है, इसलिए मेरी स्क्रिप्ट को DOM के माध्यम से नेविगेट करने और एक बार में कई पाठ नोड्स में regex को लागू करने की जरूरत है, जबकि यह पता लगाया जाए कि उसे जरूरत पड़ने पर पाठ नोड्स को विभाजित करना है।

उदाहरण के लिए, एक regex के साथ जो पूर्ण अक्षर को एक बड़े अक्षर से शुरू होता है और एक अवधि के साथ समाप्त होता है, यह दस्तावेज़:

<p> <b>HTML</b> is a language used to make <b>websites.</b> It was developed by <i>CERN</i> employees in the early 90s. <p> 

इस में बदल जाएगा:

 <p> <span><b>HTML</b> is a language used to make <b>websites.</b></span> <span>It was developed by <i>CERN</i> employees in the early 90s.</span> <p> 

स्क्रिप्ट तब सभी बनाए गए स्पेन्स की सूची वापस करता है।

मेरे पास पहले से कुछ कोड है जो सभी पाठ नोड्स को ढूंढता है और उन्हें संपूर्ण दस्तावेज़ और उनकी गहराई में अपनी स्थिति के साथ एक सूची में संग्रहीत करता है। आपको वाकई मुझे समझने की ज़रूरत नहीं है कि कोड और इसकी पुनरावर्ती संरचना थोड़ा भ्रमित हो सकती है। टी वह पहले भाग मुझे यकीन नहीं है कि कैसे करना है यह पता लगाता है कि अवधि के भीतर कौन से तत्व शामिल किए जाने चाहिए?

 function SmartNode(node, depth, start) { this.node = node; this.depth = depth; this.start = start; } function findTextNodes(node, depth, start) { var list = []; var start = start || 0; depth = (typeof depth !== "undefined" ? depth : -1); if(node.nodeType === Node.TEXT_NODE) { list.push(new SmartNode(node, depth, start)); } else { for(var i=0; i < node.childNodes.length; ++i) { list = list.concat(findTextNodes(node.childNodes[i], depth+1, start)); if(list.length) start += list[list.length-1].node.nodeValue.length; } } return list; } 

मुझे लगता है कि मैं सभी दस्तावेज़ों से एक स्ट्रिंग बना दूँगा, इसके माध्यम से regex चलाएं और सूची का उपयोग करने के लिए पता करें कि कौन-सा नोड विच रीजेक्स मैचों से मेल खाती है और फिर टेक्स्ट नोड्स को तदनुसार विभाजित करता है।

लेकिन एक समस्या आती है जब मेरे पास एक दस्तावेज है:

 <p> This program is <a href="beta.html">not stable yet. Do not use this in production yet.</a> </p> 

एक वाक्य है जो <a> टैग के बाहर शुरू होता है लेकिन उसके अंदर समाप्त होता है अब मैं स्क्रिप्ट को उस लिंक को दो टैगों में विभाजित नहीं करना चाहता। अधिक जटिल दस्तावेज़ में, यह पृष्ठ को नष्ट कर सकता है यदि यह किया था। कोड या तो दो वाक्यों को एक साथ लपेट सकता है:

 <p> <span>This program is <a href="beta.html">not stable yet. Do not use this in production yet.</a></span> </p> 

या बस प्रत्येक भाग को अपने तत्व में लपेटें:

 <p> <span>This program is </span> <a href="beta.html"> <span>not stable yet.</span> <span>Do not use this in production yet.</span> </a> </p> 

यह निर्धारित करने के लिए एक पैरामीटर हो सकता है कि उसे क्या करना चाहिए। मुझे अभी यकीन नहीं है कि एक असंभव कटौती होने के बारे में कैसे पता चलेगा , और इसे कैसे ठीक करना है

एक और मुद्दा आता है जब मेरे पास इस तरह के एक बच्चे तत्व के अंदर सफेद स्थान है :

 <p>This is a <b>sentence. </b></p> 

तकनीकी रूप से, regex मैच <b> टैग के अंत से पहले, अवधि के ठीक अंत हो जाएगा हालांकि, मैच के हिस्से के रूप में अंतरिक्ष पर विचार करना बेहतर होगा और इसे इस तरह लपेटें:

 <p><span>This is a <b>sentence. </b></span></p> 

उसके बाद यह:

 <p><span>This is a </span><b><span>sentence.</span> </b></p> 

लेकिन यह मामूली मुद्दा है सब के बाद, मैं सिर्फ अतिरिक्त सफेद स्थान को regex के भीतर शामिल करने की अनुमति दे सकता था।

मुझे पता है कि यह एक "मेरे लिए करें" प्रश्न की तरह लग सकता है और इसका हम रोज़ाना पर इतने जल्दी सवाल नहीं देखते हैं, लेकिन मैं कुछ समय के लिए इस पर अटक गया था और यह एक खुले स्रोत पुस्तकालय के लिए है मैं इस पर काम कर रहा हूं। इस समस्या को सुलझाना आखिरी बाधा है अगर आपको लगता है कि इस प्रश्न के लिए किसी अन्य एसई साइट को सबसे अच्छी तरह अनुकूल है, तो कृपया मुझे पुन: निर्देशित करें।

Solutions Collecting From Web of "कैसे जावास्क्रिप्ट के साथ एक नोड में किसी पाठ का भाग लपेटें"

इस से निपटने के दो तरीके यहां दिए गए हैं।

मुझे नहीं पता कि क्या निम्नलिखित आपकी ज़रूरतों को ठीक से पूरा करेगा। यह समस्या का एक सरल पर्याप्त समाधान है, लेकिन कम से कम यह एचटीएमएल टैगों में हेरफेर करने के लिए रेगएक्स का इस्तेमाल नहीं करता है । यह कच्चे पाठ के विरुद्ध पैटर्न मिलान करता है और फिर सामग्री को हेरफेर करने के लिए DOM का उपयोग करता है।


पहले दृष्टिकोण

यह दृष्टिकोण प्रत्येक मैच में केवल एक <span> टैग बनाता है, कुछ कम सामान्य ब्राउज़र एपीआई का लाभ उठाता है।
(डेमो के नीचे इस दृष्टिकोण की मुख्य समस्या देखें, और यदि निश्चित न हो, तो दूसरे दृष्टिकोण का उपयोग करें)

Range क्लास एक पाठ खंड का प्रतिनिधित्व करता है। इसकी एक surroundContents पास है surroundContents फ़ंक्शन जो आपको एक तत्व में रेंज लपेट देता है इसके अलावा एक चेतावनी है:

यह विधि लगभग newNode.appendChild(range.extractContents()); range.insertNode(newNode) बराबर है newNode.appendChild(range.extractContents()); range.insertNode(newNode) newNode.appendChild(range.extractContents()); range.insertNode(newNode) आसपास के बाद, सीमा के सीमा बिंदुओं में newNode शामिल newNode

एक अपवाद फेंक दिया जाएगा, हालांकि, यदि Range केवल एक सीमा बिंदु के साथ एक गैर- Text नोड को विभाजित करती है यही है, ऊपर दिए गए विकल्प के विपरीत, यदि आंशिक रूप से चयनित नोड्स हैं, तो उन्हें क्लोन नहीं किया जाएगा और इसके बजाय ऑपरेशन विफल हो जाएगा।

ठीक है, एमडीएन में समाधान दिया गया है, इसलिए सभी अच्छे हैं।

तो यहाँ एक एल्गोरिदम है:

  • Text नोड्स की एक सूची बनाएं और Text अपने शुरुआती सूचकांक रखें
  • text पाने के लिए इन नोड्स के मूल्यों को जोड़ना
  • टेक्स्ट पर मिलान ढूंढें, और प्रत्येक मैच के लिए:

    • मैच की स्थिति में नोड्स के शुरुआती सूचकांक की तुलना करते हुए, मैच के प्रारंभ और समाप्ति नोड को ढूंढें
    • मैच के ऊपर एक Range बनाएं
    • ऊपर दिए गए चाल का उपयोग करके ब्राउज़र को गंदे काम करने दें
    • अंतिम क्रिया के बाद से डोम सूची को फिर से बनाना डीओएम बदल दिया

डेमो के साथ यहां मेरा कार्यान्वयन है:

 function highlight(element, regex) { var document = element.ownerDocument; var getNodes = function() { var nodes = [], offset = 0, node, nodeIterator = document.createNodeIterator(element, NodeFilter.SHOW_TEXT, null, false); while (node = nodeIterator.nextNode()) { nodes.push({ textNode: node, start: offset, length: node.nodeValue.length }); offset += node.nodeValue.length } return nodes; } var nodes = getNodes(nodes); if (!nodes.length) return; var text = ""; for (var i = 0; i < nodes.length; ++i) text += nodes[i].textNode.nodeValue; var match; while (match = regex.exec(text)) { // Prevent empty matches causing infinite loops if (!match[0].length) { regex.lastIndex++; continue; } // Find the start and end text node var startNode = null, endNode = null; for (i = 0; i < nodes.length; ++i) { var node = nodes[i]; if (node.start + node.length <= match.index) continue; if (!startNode) startNode = node; if (node.start + node.length >= match.index + match[0].length) { endNode = node; break; } } var range = document.createRange(); range.setStart(startNode.textNode, match.index - startNode.start); range.setEnd(endNode.textNode, match.index + match[0].length - endNode.start); var spanNode = document.createElement("span"); spanNode.className = "highlight"; spanNode.appendChild(range.extractContents()); range.insertNode(spanNode); nodes = getNodes(); } } // Test code var testDiv = document.getElementById("test-cases"); var originalHtml = testDiv.innerHTML; function test() { testDiv.innerHTML = originalHtml; try { var regex = new RegExp(document.getElementById("regex").value, "g"); highlight(testDiv, regex); } catch(e) { testDiv.innerText = e; } } document.getElementById("runBtn").onclick = test; test(); 
 .highlight { background-color: yellow; border: 1px solid orange; border-radius: 5px; } .section { border: 1px solid gray; padding: 10px; margin: 10px; } 
 <form class="section"> RegEx: <input id="regex" type="text" value="[AZ].*?\." /> <button id="runBtn">Highlight</button> </form> <div id="test-cases" class="section"> <div>foo bar baz</div> <p> <b>HTML</b> is a language used to make <b>websites.</b> It was developed by <i>CERN</i> employees in the early 90s. <p> <p> This program is <a href="beta.html">not stable yet. Do not use this in production yet.</a> </p> <div>foo bar baz</div> </div> 

जैसा कि सभी ने पहले से ही कहा है, यह एक अकादमिक सवाल का अधिक है क्योंकि इससे वास्तव में ऐसा नहीं होना चाहिए। कहा जा रहा है, यह मज़ा की तरह लग रहा था तो यहाँ एक दृष्टिकोण है

संपादित करें: मुझे लगता है कि मुझे अभी इसका सार मिला है।

 function myReplace(str) { myRegexp = /((^<[^>*]>)+|([^<>\.]*|(<[^\/>]*>[^<>\.]+<\/[^>]*>)+)*[^<>\.]*\.\s*|<[^>]*>|[^\.<>]+\.*\s*)/g; arr = str.match(myRegexp); var out = ""; for (i in arr) { var node = arr[i]; if (node.indexOf("<")===0) out += node; else out += "<span>"+node+"</span>"; // Here is where you would run whichever // regex you want to match by } document.write(out.replace(/</g, "&lt;").replace(/>/g, "&gt;")+"<br>"); console.log(out); } myReplace('<p>This program is <a href="beta.html">not stable yet. Do not use this in production yet.</a></p>'); myReplace('<p>This is a <b>sentence. </b></p>'); myReplace('<p>This is a <b>another</b> and <i>more complex</i> even <b>super complex</b> sentence.</p>'); myReplace('<p>This is a <b>a sentence</b>. Followed <i>by</i> another one.</p>'); myReplace('<p>This is a <b>an even</b> more <i>complex sentence. </i></p>'); /* Will output: <p><span>This program is </span><a href="beta.html"><span>not stable yet. </span><span>Do not use this in production yet.</span></a></p> <p><span>This is a </span><b><span>sentence. </span></b></p> <p><span>This is a <b>another</b> and <i>more complex</i> even <b>super complex</b> sentence.</span></p> <p><span>This is a <b>a sentence</b>. </span><span>Followed <i>by</i> another one.</span></p> <p><span>This is a </span><b><span>an even</span></b><span> more </span><i><span>complex sentence. </span></i></p> */ 
 function parseText( element ){ var stack = [ element ]; var group = false; var re = /(?!\s|$).*?(\.|$)/; while ( stack.length > 0 ){ var node = stack.shift(); if ( node.nodeType === Node.TEXT_NODE ) { if ( node.textContent.trim() != "" ) { var match; while( node && (match = re.exec( node.textContent )) ) { var start = group ? 0 : match.index; var length = match[0].length + match.index - start; if ( start > 0 ) { node = node.splitText( start ); } var wrapper = document.createElement( 'span' ); var next = null; if ( match[1].length > 0 ){ if ( node.textContent.length > length ) next = node.splitText( length ); group = false; wrapper.className = "sentence sentence-end"; } else { wrapper.className = "sentence"; group = true; } var parent = node.parentNode; var sibling = node.nextSibling; wrapper.appendChild( node ); if ( sibling ) parent.insertBefore( wrapper, sibling ); else parent.appendChild( wrapper ); node = next; } } } else if ( node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE ) { stack.unshift.apply( stack, node.childNodes ); } } } parseText( document.body ); 
 .sentence { text-decoration: underline wavy red; } .sentence-end { border-right: 1px solid red; } 
 <p>This is a sentence. This is another sentence.</p> <p>This sentence has <strong>emphasis</strong> inside it.</p> <p><span>This sentence spans</span><span> two elements.</span></p> 

मैं इस तरह के कार्य के लिए "फ्लैट डोम" का प्रतिनिधित्व करेगा।

फ्लैट डोम में यह पैराग्राफ

 <p>abc <a href="beta.html">def. ghij.</p> 

दो वैक्टर द्वारा प्रतिनिधित्व किया जाएगा:

 chars: "abc def. ghij.", props: ....aaaaaaaaaa, 

आप प्रोजेक्टर वेक्टर पर स्पॅन क्षेत्रों को चिह्नित करने के लिए सामान्य रीगेक्सपी का उपयोग करेंगे:

 chars: "abc def. ghij." props: ssssaaaaaaaaaa ssss sssss 

मैं यहाँ योजनाबद्ध प्रतिनिधित्व का उपयोग कर रहा हूँ, यह वास्तविक संरचना सरणी की एक सरणी है:

 props: [ [s], [s], [s], [s], [a,s], [a,s], ... ] 

कनवर्ज़न पेड़- DOM <-> फ्लैट-डोम साधारण राज्य ऑटोमेटा का उपयोग कर सकता है।

अंत में आप फ्लैट DOM को टॉम DOM में बदल देंगे, जो इस तरह दिखाई देगा:

 <p><s>abc </s><a href="beta.html"><s>def.</s> <s>ghij.</s></p> 

बस के मामले में: मैं अपने एचटीएमएल WYSIWYG संपादकों में इस दृष्टिकोण का उपयोग कर रहा हूँ।