限制每行字符数并换行,同时保留前导白色 space

Limit number of characters per line and wrap while preserving leading white space

我的目标是:

我能够正确地限制每行的字符数,但是我在使用白色 space 等方面遇到了问题...

如有任何帮助,我们将不胜感激

Fiddle

var str = `i am a string that has new lines and whitespace. I need to preserve the leading whitespace and add it back on after the string has been broken up after n characters.

     This line has leading whitespace. Tttttt rrrrrr  
     ttgvgggjjj. Gyjfry bh jkkfrtuj hhdt iihdrtttg.
     Here is another line. Hjkkl gggdetu jcfgjbfftt.
This line has no leading whitespace, so i dont need any reapplied. Jjjxsrg bjlkdetyhk llhfftt`;

function addNewlines(str) { 
    var result = ''; 
    while(str.length > 0) { 
          result += str.substring(0, 25) + '<br />'; 
          str = str.substring(25); 
    } 

    return result; 
}

var newStr = addNewlines(str).toString();
document.getElementById("result").innerHTML = newStr;

最终应该看起来像这样:

i am a string that has ne
w lines and whitespace. I
need to preserve the lea
ding whitespace and add i
t back on after the strin
g has been broken up afte
r n characters. 

   This line has leading
   whitespace. Tttttt rr
   rrrr ttgvgggjjj. Gyjf
   ry bh jkkfrtuj hhdt i
   ihdrtttg. Here is ano
   ther line. Hjkkl gggd
   etu jcfgjbfftt. 

This line has no leading
 whitespace, so i dont n
 eed any reapplied. Jjjx
 srg bjlkdetyhk llhfftt

通用逻辑

您的字符串已包含全白space。如果您将 console.log(newStr) 添加到您的脚本并查看您的控制台,您会看到白色的 space 已经存在。

您可能想要删除所有结尾的白色spaces(新行字符开始前的白色spaces)。您可以通过使用正则表达式替换来做到这一点:var newStr = addNewlines(str).toString().replace(/\s+(?=\n)/g, "");.

此外,由于所有 Tab-Characters ("\t") 都将被识别为仅 1 个字符,但比其他字符占用更多 space,您可能希望将它们替换为 3 个或4 spaces 代替。类似于 .replace(/\t/g, " ")

另一件需要考虑的事情是之前已经存在的换行符。你会想在那里停止计数并在已经存在的换行符之后开始一个新的计数器。

在文本区域内显示

var str = `i am a string that has new lines and whitespace. I need to preserve the leading whitespace and add it back on after the string has been broken up after n characters.

    This line has leading whitespace. Tttttt rrrrrr  
    ttgvgggjjj. Gyjfry bh jkkfrtuj hhdt iihdrtttg.
    Here is another line. Hjkkl gggdetu jcfgjbfftt.
  This line has no leading whitespace, so i dont need any reapplied. Jjjxsrg bjlkdetyhk llhfftt`;

function addNewlines(str) { 
  var result = ''; 
  str = str.replace(/\t/g, "   ");
  
  while(str.length > 0) { 
      nPos = str.indexOf("\n");
      len = nPos > 0 && nPos < 25 ? nPos + 1 : 25;

      result += str.substring(0, len) + '\n'; 
      str = str.substring(len); 
  } 

  return result; 
}


var newStr = addNewlines(str).toString().replace(/\s+(?=\n)/g, "");
document.getElementById("result").value = newStr;
<textarea id="result"></textarea>

显示在HTML

如果你想在HTML中显示那些白色space,那么你可以使用CSS 属性 white-space: pre

var str = `i am a string that has new lines and whitespace. I need to preserve the leading whitespace and add it back on after the string has been broken up after n characters.

    This line has leading whitespace. Tttttt rrrrrr  
    ttgvgggjjj. Gyjfry bh jkkfrtuj hhdt iihdrtttg.
    Here is another line. Hjkkl gggdetu jcfgjbfftt.
  This line has no leading whitespace, so i dont need any reapplied. Jjjxsrg bjlkdetyhk llhfftt`;

  function addNewlines(str) { 
   var result = ''; 
      str = str.replace(/\t/g, "   ");
   while(str.length > 0) { 
          nPos = str.indexOf("<br />");
          len = nPos > 0 && nPos < 25 ? nPos + 1 : 25;
          
      result += str.substring(0, len) + '\n'; 
      str = str.substring(len); 
   } 

   return result; 
  }
    
    
  var newStr = addNewlines(str).toString().replace(/\s+(?=\n)/g, "");
  console.log(newStr);
  document.getElementById("result1").innerHTML = newStr;
  document.getElementById("result2").innerHTML = newStr;
  document.getElementById("result3").innerHTML = newStr;
  document.getElementById("result4").innerHTML = newStr;
  document.getElementById("result5").innerHTML = newStr;
div {

font-family: monospace;
}
<h1>normal</h1>
 <div id="result1" style="white-space: normal"></div>
    <h1>pre</h1>
 <div id="result2" style="white-space: pre"></div>
    <h1>nowrap</h1>
 <div id="result3" style="white-space: nowrap"></div>
    <h1>pre-wrap</h1>
 <div id="result4" style="white-space: pre-wrap"></div>
    <h1>pre-line</h1>
 <div id="result5" style="white-space: pre-line"></div>

此外,在您的示例中,您使用制表符来缩进行。如果你也想删除那些,那么你必须删除所有出现的那些。您可以使用另一个正则表达式和这样的替换方法来做到这一点:var newStr = addNewlines(str).toString().replace(/\s+(?=\n)/g, "").replace(/\t/g, "");.

有时在处理新算法时,使用两次或更多遍会更容易。所以你认为它是如何一步步工作的,而不是一次完成所有工作。

我有一个有 2 个通道的实现:首先我加入段落行,在第二个通道中我执行实际的拆分。

我确信有更好的方法,但这行得通并且有充分的评论。

我不确定你的 ES 版本,所以我让它与 ES5 兼容。

https://jsfiddle.net/2ngtj3aj/

// Divides a string into chunks of specific size
function chunk(str, size) {
  var chunks = [];
  while(str) { 
    chunks.push(str.substring(0, size));
    str = str.substring(size);
  }
  return chunks;
}

// Removes all spaces from the left of a string
function trimLeft(str) {
  while(str.substr(0,1) == " ") {
    str = str.substr(1);
  }
  return str;
}

// Repeats a character n times
function repeat(c, n) {
  return Array(n + 1).join(c);
}

function addNewlines(str) { 
    var MAX_COLS = 25; // maximum colums on the text
    var DEFAULT_LEADING = 3; // default leading to reapply
    var MIN_LEADING = 1; // minimum amount of spacing to be considered a paragraph
    var CR = "\n";
    var result = '';
    var leading = 0;
    var chunks = [];
    var formattedLines = []; // store the intermediary lines
    var startLeadingSpaceLine = -1; // where does a paragrph start
    var i, l; // counters
    var lines = str.split(CR); // input lines
    
    // In the first pass, we join the paragraph lines
    
    for (i = 0; i < lines.length; i++) {
    
      l = lines[i];
      // If line is empty, we don't use it
      if (l.trim() == "") continue;

      if (l.substr(0, MIN_LEADING) == repeat(" ", MIN_LEADING)) {
        // If line has leading whitespace, remove the leading space
        l = trimLeft(l);
        if (startLeadingSpaceLine > -1) {
          // If we are already on a paragraph,
          // we don't overwrite the flag
        } else {
          // But if this is the first line of an paragraph,
          // We set a flag to allow to join this line with the next one
          // if that contains identation as well
          startLeadingSpaceLine = i;
        }
        // If we are on a paragraph, we don't add this line to the array,
        // first we need to wait to see if we have more lines in the paragraph
        // We also update the line in the array with the whitespace removed
        lines[i] = l;
        continue;
      } else {
        // If line doesn't has whitespace, we check if we have just finished
        // an paragraph
        if (startLeadingSpaceLine > -1) {
          // If we do, then we need to add the previous lines to the array
          // Note: if we want to leave a space between lines, we need to use
          // join(' ') instead of join('')
          var paragraphLines = lines.slice(startLeadingSpaceLine, i).join('');
          // We add the whitespace we like
          paragraphLines = repeat(" ", DEFAULT_LEADING) + paragraphLines;
          formattedLines.push(paragraphLines);
        }
        
      }
      formattedLines.push(l);
    }
    
    // Now we parse again the lines, this time we will divide
    // the lines into chunks
    
    for (i = 0; i < formattedLines.length; i++) {
    
      l = formattedLines[i];

      // Now check against DEFAULT_LEADAING since we have already changed
      // the identation
      if (l.substr(0, DEFAULT_LEADING) == repeat(" ", DEFAULT_LEADING)) {
        
        // If line has leading whitespace, remove the leading space
        // We aded it before just to be able to detect the paragraph.
        l = trimLeft(l);
        
        // Divide the line into chunks. We take into account the space
        // we have removed, otherwise the paragraph will bleed to the
        // right.
        l = chunk(l, MAX_COLS - DEFAULT_LEADING);
        
        // We add leading space to all paragraph lines
        for(var j = 0; j < l.length; j++) {
          l[j] = repeat(" ", DEFAULT_LEADING) + l[j];
        }
        
        // Optional: we add blank lines between paragraphs
        l = [" "].concat(l).concat([" "]);
        
      } else {
      
        // If we have a simple line, just divide it into chunks
        l = chunk(l, MAX_COLS);

   }
      
      // Join the lines with newlines and add to the result
      l = l.join(CR);
      result += l + CR;
    }
    
    
    return result; 
}

var process = function() {
 var newStr = addNewlines(input.value).toString();
 document.getElementById("result").innerHTML = newStr;
}

var input = document.getElementById("input");
input.addEventListener("change", process);
input.addEventListener("keyup", process);
process();
<h3>RESULTS</h3>

<textarea id="input" rows="10" cols="80">i am a string that has new lines and whitespace. I need to preserve the leading whitespace and add it back on after the string has been broken up after n characters.

     This line has leading whitespace. Tttttt rrrrrr  
     ttgvgggjjj. Gyjfry bh jkkfrtuj hhdt iihdrtttg.
     Here is another line. Hjkkl gggdetu jcfgjbfftt.
This line has no leading whitespace, so i dont need any reapplied. Jjjxsrg bjlkdetyhk llhfftt</textarea>
<pre id="result"></pre>