2011-05-05 8 views
11

मैं एक जावास्क्रिप्ट रेगेक्स को किसी दिए गए प्रारंभ (<span>) और अंत टैग (यानी </span>) में शब्दों की एक दी गई सूची को लपेटना चाहता हूं, लेकिन केवल अगर शब्द वास्तव में " । http://jsfiddle.net/4YCR6/1/एचटीएमएल विशेषताओं में पाठ को प्रतिस्थापित करने के लिए जावास्क्रिप्ट रेगेक्स

+0

देखें http://stackoverflow.com/questions/3241169/highlight-search-terms-select-only-leaf-nodes – Ryan

+0

दूसरों के रूप में ने कहा, आमतौर पर एचटीएमएल को रेगेक्स के साथ संभालने का सबसे अच्छा विचार नहीं है। लेकिन ऐसे मामले हैं जहां यह सबसे आसान तरीका है। इसे आज़माएं: [अद्यतन jsfiddle] (http://jsfiddle.net/4YCR6/4/) [rubular] पर (http://rubular.com/r/NMazXVpKfE) – morja

उत्तर

36

: पृष्ठ पर दिखाई दे रहे पाठ ", और नहीं किसी html विशेषता के अंदर (जैसे एक कड़ी के शीर्षक टैग के रूप में, या एक <script></script> ब्लॉक के अंदर

मैं मूल बातें सेटअप के साथ एक जे एस फिडल बना लिया है एचटीएमएल एक नियमित अभिव्यक्ति के साथ विश्वसनीय रूप से पार्स करने के लिए बहुत जटिल है।

यदि आप वें करना चाहते हैं क्लाइंट-साइड है, आप एक दस्तावेज़ खंड बना सकते हैं और/या डिस्कनेक्ट किए गए डोम नोड (जिनमें से कोई भी कहीं भी प्रदर्शित नहीं होता है) और इसे अपने HTML स्ट्रिंग के साथ प्रारंभ करें, फिर परिणामी डीओएम पेड़ के माध्यम से चलें और टेक्स्ट नोड्स को संसाधित करें। (या ऐसा करने में आपकी सहायता के लिए लाइब्रेरी का उपयोग करें, हालांकि यह वास्तव में काफी सरल है।)

यहां एक डोम चलने का उदाहरण है। यह उदाहरण थोड़ा आपकी समस्या से सरल है क्योंकि यह केवल पाठ को अपडेट करता है, यह संरचना में नए तत्व नहीं जोड़ता है (span में पाठ के हिस्सों को लपेटने से संरचना को अद्यतन करना शामिल है), लेकिन यह आपको जाना चाहिए। अंत में बदलने के लिए आपको क्या करना होगा इस पर नोट्स।

var html = 
    "<p>This is a test.</p>" + 
    "<form><input type='text' value='test value'></form>" + 
    "<p class='testing test'>Testing here too</p>"; 
var frag = document.createDocumentFragment(); 
var body = document.createElement('body'); 
var node, next; 

// Turn the HTML string into a DOM tree 
body.innerHTML = html; 

// Walk the dom looking for the given text in text nodes 
walk(body); 

// Insert the result into the current document via a fragment 
node = body.firstChild; 
while (node) { 
    next = node.nextSibling; 
    frag.appendChild(node); 
    node = next; 
} 
document.body.appendChild(frag); 

// Our walker function 
function walk(node) { 
    var child, next; 

    switch (node.nodeType) { 
    case 1: // Element 
    case 9: // Document 
    case 11: // Document fragment 
     child = node.firstChild; 
     while (child) { 
     next = child.nextSibling; 
     walk(child); 
     child = next; 
     } 
     break; 
    case 3: // Text node 
     handleText(node); 
     break; 
    } 
} 

function handleText(textNode) { 
    textNode.nodeValue = textNode.nodeValue.replace(/test/gi, "TEST"); 
} 

Live example

परिवर्तन आप handleText में होगा बनाने की आवश्यकता होगी। विशेष रूप से, बल्कि nodeValue को अद्यतन करने के बजाय, आप की आवश्यकता होगी करने के लिए:

  • nodeValue स्ट्रिंग में प्रत्येक शब्द की शुरुआत के सूचकांक का पता लगाएं।
  • टेक्स्ट नोड को तीन टेक्स्ट नोड्स में विभाजित करने के लिए Node#splitText का उपयोग करें (आपके मिलान करने वाले पाठ से पहले भाग, आपके मिलान करने वाले पाठ और आपके मिलान करने वाले पाठ के बाद का हिस्सा है)।
  • नया span बनाने के लिए document.createElement का उपयोग करें (यह सचमुच केवल span = document.createElement('span') है)।
  • तीसरे पाठ नोड के सामने नया span डालने के लिए Node#insertBefore का उपयोग करें (जिसमें आपके मिलान किए गए पाठ के बाद पाठ वाला एक है); यह ठीक है अगर आपको तीसरा नोड बनाने की आवश्यकता नहीं है क्योंकि आपका मिलान टेक्स्ट टेक्स्ट नोड के अंत में था, तो refChild के रूप में बस null में पास करें।
  • में दूसरे टेक्स्ट नोड (मिलान करने वाले पाठ वाला एक) को स्थानांतरित करने के लिए Node#appendChild का उपयोग करें। (इसे अपने माता-पिता से पहले हटाने की आवश्यकता नहीं है; appendChild आपके लिए यह करता है।)
+9

मजेदार तथ्य: लगभग पांच साल बाद, उन्होंने इसका उपयोग किया [ड्रम्पफिनेटर क्रोम एक्सटेंशन] में कोड (http://drumpfinator.com/) जॉन ओलिवर के साथ * पिछले सप्ताह आज रात * से जुड़ा हुआ है। प्रफुल्लित! –

+0

आपने इसे भी पाया है? अरे इंतज़ार करो यह तुम्हारा जवाब है? क्या आपने परामर्श किया था या आपने मेरे जैसे विस्तार में देखा था? – brace110

+1

@ ब्रेस 110: स्रोत कोड पर नजर रखने वाली एक बहुत अच्छी युवा महिला ने मुझे एक ईमेल छोड़ दिया। :-) –

7

T.J. Crowder's answer सही है। मैं थोड़ी और कोड-वार चला गया हूं: यहां एक पूरी तरह से गठित उदाहरण है जो सभी प्रमुख ब्राउज़रों में काम करता है। मैंने स्टैक ओवरफ़्लो पर इस कोड के विविधताएं पोस्ट की हैं (here और here, उदाहरण के लिए), और इसे अच्छा और सामान्य बना दिया है इसलिए मैंने (या किसी और को) इसे पुन: उपयोग करने के लिए बहुत कुछ नहीं बदला है।

jsFiddle उदाहरण: http://jsfiddle.net/7Vf5J/38/

कोड:

// Reusable generic function 
function surroundInElement(el, regex, surrounderCreateFunc) { 
    // script and style elements are left alone 
    if (!/^(script|style)$/.test(el.tagName)) { 
     var child = el.lastChild; 
     while (child) { 
      if (child.nodeType == 1) { 
       surroundInElement(child, regex, surrounderCreateFunc); 
      } else if (child.nodeType == 3) { 
       surroundMatchingText(child, regex, surrounderCreateFunc); 
      } 
      child = child.previousSibling; 
     } 
    } 
} 

// Reusable generic function 
function surroundMatchingText(textNode, regex, surrounderCreateFunc) { 
    var parent = textNode.parentNode; 
    var result, surroundingNode, matchedTextNode, matchLength, matchedText; 
    while (textNode && (result = regex.exec(textNode.data))) { 
     matchedTextNode = textNode.splitText(result.index); 
     matchedText = result[0]; 
     matchLength = matchedText.length; 
     textNode = (matchedTextNode.length > matchLength) ? 
      matchedTextNode.splitText(matchLength) : null; 
     // Ensure searching starts at the beginning of the text node 
     regex.lastIndex = 0; 
     surroundingNode = surrounderCreateFunc(matchedTextNode.cloneNode(true)); 
     parent.insertBefore(surroundingNode, matchedTextNode); 
     parent.removeChild(matchedTextNode); 
    } 
} 

// This function does the surrounding for every matched piece of text 
// and can be customized to do what you like 
function createSpan(matchedTextNode) { 
    var el = document.createElement("span"); 
    el.style.color = "red"; 
    el.appendChild(matchedTextNode); 
    return el; 
} 

// The main function 
function wrapWords(container, words) { 
    // Replace the words one at a time to ensure "test2" gets matched 
    for (var i = 0, len = words.length; i < len; ++i) { 
     surroundInElement(container, new RegExp(words[i]), createSpan); 
    } 
} 

wrapWords(document.getElementById("container"), ["test2", "test"]); 
+0

यह वही है जो मैं ढूंढ रहा था, हालांकि मैं इसे पूरी तरह से अनदेखा कैसे कर सकता हूं? –

+1

@ माइकमेलर: 'नया RegExp बदलें (शब्द [i], "g") '' 'नया RegExp (शब्द [i]," gi ")'। –

+0

ईश्वर जो आसान था, मुझे वास्तव में नियमित अभिव्यक्तियों के बारे में जानना चाहिए। धन्यवाद टिम –

संबंधित मुद्दे

 संबंधित मुद्दे