Рендеринг текста в HTML, сохраняя пробелы – без

учитывая любой произвольный текстовый файл, полный печатаемых символов, как это можно преобразовать в HTML, который будет отображаться точно так же (со следующими требованиями)?

  • не полагается ни на какие, кроме правил HTML пробелов по умолчанию
    • нет <pre> tag
    • нет CSS white-space правила
  • <p> теги в порядке, но не требуются (<br />и/или <div>С отлично)
  • пробелы поддерживаются точно.

    учитывая следующие строки ввода (игнорировать ошибочную подсветку авто синтаксиса):

    Line one
        Line two, indented    four spaces
    

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

    учитывая две строки как полный входной файл, пример правильного вывода будет:

    Line one<br />&nbsp;&nbsp;&nbsp;&nbsp;Line two, 
    indented&nbsp;&nbsp;&nbsp; four spaces
    
  • желательно мягкое обертывание в браузере. То есть полученный HTML не должен заставлять пользователя прокручивать, даже если входные строки шире, чем их видовое окно (при условии, что отдельные слова все еще сужаются, чем указанное видовое окно).

Я ищу полностью определен . бонусные баллы за реализацию в питон или javascript.

(пожалуйста, не просто ответ, что я должен использовать <pre> теги или CSS white-space правило, поскольку мои требования делают эти параметры несостоятельными. Пожалуйста, также не публикуйте непроверенные и / или наивные предложения, такие как "заменить все пробелы на &nbsp;."В конце концов, я уверен, что решение технически возможно - это интересная проблема, не так ли?)

4 ответов


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

браузер правильно отобразит все пробелы (нормальные и не разрывные), при этом все еще обертывая длинные строки (из-за нормальных пробелов).

Javascript:

text = html_escape(text); // dummy function
text = text.replace(/\t/g, '    ')
           .replace(/  /g, '&nbsp; ')
           .replace(/  /g, ' &nbsp;') // second pass
                                      // handles odd number of spaces, where we 
                                      // end up with "&nbsp;" + " " + " "
           .replace(/\r\n|\n|\r/g, '<br />');

использовать нулевой ширины пространства (&#8203;), чтобы сохранить пробелы и разрешить перенос текста. Основная идея состоит в том, чтобы соединить каждое пространство или последовательность пространств с пространством нулевой ширины. Затем заменить каждый пробел на неразрывный пробел. Вы также захотите кодировать html и добавлять разрывы строк.

если вас не волнуют символы юникода, это тривиально. Вы можете просто использовать string.replace():

function textToHTML(text)
{
    return ((text || "") + "")  // make sure it is a string;
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/\t/g, "    ")
        .replace(/ /g, "&#8203;&nbsp;&#8203;")
        .replace(/\r\n|\r|\n/g, "<br />");
}

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

    .replace(/ /g, "&nbsp;")
    .replace(/((&nbsp;)+)/g, "&#8203;&#8203;")

чтобы кодировать символы юникода, это немного сложнее. Вам нужно повторить строку:

var charEncodings = {
    "\t": "&nbsp;&nbsp;&nbsp;&nbsp;",
    " ": "&nbsp;",
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    "\n": "<br />",
    "\r": "<br />"
};
var space = /[\t ]/;
var noWidthSpace = "&#8203;";
function textToHTML(text)
{
    text = (text || "") + "";  // make sure it is a string;
    text = text.replace(/\r\n/g, "\n");  // avoid adding two <br /> tags
    var html = "";
    var lastChar = "";
    for (var i in text)
    {
        var char = text[i];
        var charCode = text.charCodeAt(i);
        if (space.test(char) && !space.test(lastChar) && space.test(text[i + 1] || ""))
        {
            html += noWidthSpace;
        }
        html += char in charEncodings ? charEncodings[char] :
        charCode > 127 ? "&#" + charCode + ";" : char;
        lastChar = char;
    }
    return html;
}  

теперь, просто комментарий. Без использования шрифтов monospace вы потеряете форматирование. Рассмотрим, как эти строки текста с помощью шрифта monospace образуют столбцы:

ten       seven spaces
eleven    four spaces

без шрифта monospaced, вы потеряет столбцы:

десять семь пространств
 одиннадцать четыре места

кажется, что алгоритм для исправления этого будет очень сложным.


хотя это не совсем соответствует всем вашим требованиям - во-первых, он не обрабатывает вкладки, я использовал следующий драгоценный камень, который добавляет wordWrap() метод для Javascript Strings, пару раз сделать что - то похожее на то, что вы описываете-так что это может быть хорошей отправной точкой, чтобы придумать что-то, что также делает дополнительные вещи, которые вы хотите.

//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/string/wordwrap [rev. #2]

// String.wordWrap(maxLength: Integer,
//                 [breakWith: String = "\n"],
//                 [cutType: Integer = 0]): String
//
//   Returns an string with the extra characters/words "broken".
//
//     maxLength  maximum amount of characters per line
//     breakWith  string that will be added whenever one is needed to
//                break the line
//     cutType    0 = words longer than "maxLength" will not be broken
//                1 = words will be broken when needed
//                2 = any word that trespasses the limit will be broken

String.prototype.wordWrap = function(m, b, c){
    var i, j, l, s, r;
    if(m < 1)
        return this;
    for(i = -1, l = (r = this.split("\n")).length; ++i < l; r[i] += s)
        for(s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : ""))
            j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length
            || c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length;
    return r.join("\n");
};

Я также хотел бы прокомментировать, что мне кажется, что, в общем, вы хотели бы использовать моноширинный шрифт, если вкладки задействованы, потому что ширина слов будет меняться в зависимости от используемого пропорционального шрифта (что делает результаты использования табуляции очень зависимыми от шрифта).

обновление: вот немного более читаемая версия любезно предоставлена онлайн javascript beautifier:

String.prototype.wordWrap = function(m, b, c) {
    var i, j, l, s, r;
    if (m < 1)
        return this;
    for (i = -1, l = (r = this.split("\n")).length; ++i < l; r[i] += s)
        for (s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s =
                s.slice(j)).length ? b : ""))
            j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m :
            j.input.length - j[0].length || c == 1 && m || j.input.length +
            (j = s.slice(m).match(/^\S*/)).input.length;
    return r.join("\n");
};

- Это очень просто, если вы используете библиотеку jQuery в вашем проекте.

только одна строка, добавить asHTml расширение до класса String и:

var plain='&lt;a&gt; i am text plain &lt;/a&gt;'
plain.asHtml();
/* '<a> i am text plain </a>' */

демо:http://jsfiddle.net/abdennour/B6vGG/3/

Примечание: вам не придется обращаться к DoM . Просто используйте шаблон дизайна builder jQuery $('<tagName />')