Regexp для поиска / замены только текста, а не в атрибуте HTML - PullRequest
4 голосов
/ 11 августа 2010

Я использую JavaScript для создания некоторых регулярных выражений.Учитывая, что я работаю с правильно сформированным источником, и я хочу удалить любой пробел перед [,.] и оставить только один пробел после [,.], За исключением того, что [,.] Является частью числа.Поэтому я использую:

text = text.replace(/ *(,|\.) *([^ 0-9])/g, '$1 $2');

Проблема в том, что это заменяет также текст в атрибутах тега html.Например, мой текст (всегда обернутый тегом):

<p>Test,and test . Again <img src="xyz.jpg"> ...</p>

Теперь он добавляет такой пробел, как этот src="xyz. jpg", который не ожидается.Как я могу переписать свое регулярное выражение?То, что я хочу, это

<p>Test, and test. Again <img src="xyz.jpg"> ...</p>

Спасибо!

Ответы [ 6 ]

4 голосов
/ 12 августа 2010

Вы можете использовать предпросмотр, чтобы убедиться, что в теге нет совпадения:

text = text.replace(/(?![^<>]*>) *([.,]) *([^ \d])/g, '$1 $2');

Обычные предупреждения относятся к разделам CDATA, комментариям SGML, элементам SCRIPT и угловым скобкам в значениях атрибутов.,Но я подозреваю, что ваши настоящие проблемы возникнут из капризов "простого" текста;HTML даже не в той же лиге.: D

1 голос
/ 11 августа 2010

Если вы можете получить доступ к этому тексту через DOM, вы можете сделать это:

function fixPunctuation(elem) {
    // check if parameter is a an ELEMENT_NODE
    if (!(elem instanceof Node) || elem.nodeType !== Node.ELEMENT_NODE) return;
    var children = elem.childNodes, node;
    // iterate the child nodes of the element node
    for (var i=0; children[i]; ++i) {
        node = children[i];
        // check the child’s node type
        switch (node.nodeType) {
        case Node.ELEMENT_NODE:
            // call fixPunctuation if it’s also an ELEMENT_NODE
            fixPunctuation(node);
            break;
        case Node.TEXT_NODE:
            // fix punctuation if it’s a TEXT_NODE
            node.nodeValue = node.nodeValue.replace(/ *(,|\.) *([^ 0-9])/g, '$1 $2');
            break;
        }
    }
}

Теперь просто передайте узел DOM этой функции следующим образом:

fixPunctuation(document.body);
fixPunctuation(document.getElementById("foobar"));
1 голос
/ 11 августа 2010

Не пытайтесь переписать ваше выражение, чтобы сделать это. Вы не добьетесь успеха и почти наверняка забудете о некоторых угловых делах. В лучшем случае это приведет к неприятным ошибкам, а в худшем - к проблемам с безопасностью.

Вместо этого, когда вы уже используете JavaScript и имеете правильно сформированный код, используйте подлинный синтаксический анализатор XML для зацикливания текстовых узлов и применяйте к ним только свое регулярное выражение.

0 голосов
/ 11 августа 2010

Как указано выше и много раз ранее, HTML не является обычным языком и, следовательно, не может быть проанализирован с помощью регулярных выражений.

Вам придется делать это рекурсивно;Я бы предложил сканировать объект DOM.

Попробуйте что-то вроде этого ...

function regexReplaceInnerText(curr_element) {
    if (curr_element.childNodes.length <= 0) { // termination case:
                                               // no children; this is a "leaf node"
        if (curr_element.nodeName == "#text" || curr_element.nodeType == 3) { // node is text; not an empty tag like <br />
            if (curr_element.data.replace(/^\s*|\s*$/g, '') != "") { // node isn't just white space
                                                                     // (you can skip this check if you want)
                var text = curr_element.data;
                text = text.replace(/ *(,|\.) *([^ 0-9])/g, '$1 $2');
                curr_element.data = text;
            }
        }
    } else {
        // recursive case:
        // this isn't a leaf node, so we iterate over all children and recurse
        for (var i = 0; curr_element.childNodes[i]; i++) {
            regexReplaceInnerText(curr_element.childNodes[i]);
        }
    }
}
// then get the element whose children's text nodes you want to be regex'd
regexReplaceInnerText(document.getElementsByTagName("body")[0]);
// or if you don't want to do the whole document...
regexReplaceInnerText(document.getElementById("ElementToRegEx"));
0 голосов
/ 11 августа 2010

Не анализировать регулярное выражение HTML с HTML регулярное выражение . Если вы знаете, что ваш HTML правильно сформирован, используйте анализатор HTML / XML. В противном случае сначала запустите его через Tidy, а затем используйте синтаксический анализатор XML.

0 голосов
/ 11 августа 2010

HTML не является «обычным языком», поэтому регулярное выражение не является оптимальным инструментом для его анализа. Возможно, вам лучше использовать такой синтаксический анализатор html, как этот, чтобы получить атрибут , а затем применить регулярное выражение, чтобы сделать что-то со значением.

Наслаждайтесь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...