web-dev-qa-db-ja.com

JavaScriptでテキストを折り返す

JavaScriptとjQueryは初めてです。

JavaScriptにstrという名前の変数があり、次のような非常に長いテキストが含まれています

"A quick brown fox jumps over a lazy dog". 

正しい場所に適切な\nまたはbr/タグを挿入して、それをラップして同じ変数strに割り当てたいと思います。

CSSなどを使用したくないのですが、strを受け取って適切な形式のテキストを返すJavaScriptの適切な関数でそれを行う方法を教えてください。

何かのようなもの:

str = somefunction(str, maxchar);

何度も試してみましたが、残念ながら思い通りになりませんでした! :(

どんな助けでも大歓迎です...

17
user2004685

これにより、maxCharの最も近い空白に改行が挿入されます。

str = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It w as popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";

str = wordWrap(str, 40);

function wordWrap(str, maxWidth) {
    var newLineStr = "\n"; done = false; res = '';
    while (str.length > maxWidth) {                 
        found = false;
        // Inserts new line at first whitespace of the line
        for (i = maxWidth - 1; i >= 0; i--) {
            if (testWhite(str.charAt(i))) {
                res = res + [str.slice(0, i), newLineStr].join('');
                str = str.slice(i + 1);
                found = true;
                break;
            }
        }
        // Inserts new line at maxWidth position, the Word is too long to wrap
        if (!found) {
            res += [str.slice(0, maxWidth), newLineStr].join('');
            str = str.slice(maxWidth);
        }

    }

    return res + str;
}

function testWhite(x) {
    var white = new RegExp(/^\s$/);
    return white.test(x.charAt(0));
};
22
ieeehh

この質問はかなり古いですが、user2257198が指摘したように、これまでに提供された多くのソリューションは必要以上に複雑で高価です-これは短い1行の正規表現で完全に解決できます。

しかし、私は彼の解決策にいくつかの問題を見つけました:wrapping after以前よりも最大幅、文字クラスに明示的に含まれていない文字を改行し、既存の改行文字を考慮せずに段落の開始が途切れる正中線。

それで私は自分の解決策を書くことにしました:

// Static Width (Plain Regex)
const wrap = (s, w) => s.replace(
    /(?![^\n]{1,32}$)([^\n]{1,32})\s/g, '$1\n'
);

// Dynamic Width (Build Regex)
const wrap = (s, w) => s.replace(
    new RegExp(`(?![^\\n]{1,${w}}$)([^\\n]{1,${w}})\\s`, 'g'), '$1\n'
);

ボーナス機能

  • 処理any改行ではない文字(コ​​ードなど)。
  • 既存の改行を適切に処理します(例:段落)。
  • 改行の先頭にスペースを入れないようにします。
  • 文字列の最後に不要な改行を追加しないようにします。

説明

主な概念は、notが希望する長さまでの改行[^\n]を含む、連続する文字のシーケンスを単に見つけることです(例:32 {1,32})。文字クラスで否定^を使用することで、はるかに許容範囲が広くなり、句読点などの明示的に追加する必要のあるものの欠落を回避できます。

str.replace(/([^\n]{1,32})/g, '[$1]\n');
// Matches wrapped in [] to help visualise

"[Lorem ipsum dolor sit amet, cons]
[ectetur adipiscing elit, sed do ]
[eiusmod tempor incididunt ut lab]
[ore et dolore magna aliqua.]
"

これまでのところ、これは文字列をちょうど32文字でスライスするだけです。それはそれ自身の改行挿入が最初の後に各シーケンスの開始をマークするので機能します。

単語を分割するには、貪欲な量指定子{1,32}の後に修飾子が必要です。これは、単語の途中で終わるシーケンスを選択できないようにするためです。ワードブレーク文字\bは、新しい行の先頭にスペースを生じさせる可能性があるため、代わりに空白文字\sを使用する必要があります。また、最大幅が1文字増えるのを防ぐために、グループの外側に配置して食べる必要があります。

str.replace(/([^\n]{1,32})\s/g, '[$1]\n');
// Matches wrapped in [] to help visualise

"[Lorem ipsum dolor sit amet,]
[consectetur adipiscing elit, sed]
[do eiusmod tempor incididunt ut]
[labore et dolore magna]
aliqua."

現在は制限の前の単語で中断しますが、最後の単語とピリオドは、終了スペースがないため、最後のシーケンスでは一致しませんでした。

「または文字列の終わり」オプション(\s|$)を空白に追加して一致を拡張することもできますが、最後の行との一致を防ぐ方がより適切ですすべて不要な改行が最後に挿入されます。これを実現するには、まったく同じシーケンスの否定先読みを追加できますbeforeですが、空白文字の代わりに文字列の終わり文字を使用します。

str.replace(/(?![^\n]{1,32}$)([^\n]{1,32})\s/g, '[$1]\n');
// Matches wrapped in [] to help visualise

"[Lorem ipsum dolor sit amet,]
[consectetur adipiscing elit, sed]
[do eiusmod tempor incididunt ut]
labore et dolore magna aliqua."
28
Thomas Brierley

これは少し短い解決策です:

var str = "This is a very long line of text that we are going to use in this example to divide it into rows of maximum 40 chars."

var result = stringDivider(str, 40, "<br/>\n");
console.log(result);

function stringDivider(str, width, spaceReplacer) {
    if (str.length>width) {
        var p=width
        for (;p>0 && str[p]!=' ';p--) {
        }
        if (p>0) {
            var left = str.substring(0, p);
            var right = str.substring(p+1);
            return left + spaceReplacer + stringDivider(right, width, spaceReplacer);
        }
    }
    return str;
}

この関数は再帰を使用して問題を解決します。

13
javabeangrinder

私の亜種。単語はそのまま保持されるので、必ずしもmaxChars基準を満たしているとは限りません。

function wrapText(text, maxChars) {
        var ret = [];
        var words = text.split(/\b/);

        var currentLine = '';
        var lastWhite = '';
        words.forEach(function(d) {
            var prev = currentLine;
            currentLine += lastWhite + d;

            var l = currentLine.length;

            if (l > maxChars) {
                ret.Push(prev.trim());
                currentLine = d;
                lastWhite = '';
            } else {
                var m = currentLine.match(/(.*)(\s+)$/);
                lastWhite = (m && m.length === 3 && m[2]) || '';
                currentLine = (m && m.length === 3 && m[1]) || currentLine;
            }
        });

        if (currentLine) {
            ret.Push(currentLine.trim());
        }

        return ret.join("\n");
    }
3
Stephan

このような多くの動作は、正規表現を使用して単一ライナーとして実現できます(必要な動作に応じて、最小数の一致する文字を含む貪欲でない数量詞、または最大文字数を含む貪欲な数量詞を使用)。

以下では、貪欲ではないグローバル置換がNode V8 REPL内で機能しているので、コマンドと結果を確認できます。ただし、ブラウザでも同じように機能するはずです。

このパターンは、定義されたグループ(\ wはWord文字を意味し、\ sは空白文字を意味する)に一致する少なくとも10文字を検索し、\ b Word境界に対してパターンをアンカーします。次に、後方参照を使用して、元の一致を改行が追加されたものに置き換えます(この場合、オプションで、括弧で囲まれた後方参照に取り込まれていないスペース文字を置き換えます)。

> s = "This is a paragraph with several words in it."
'This is a paragraph with several words in it.'
> s.replace(/([\w\s]{10,}?)\s?\b/g, "$1\n")
'This is a \nparagraph \nwith several\nwords in it\n.'

元のポスターの要求された形式では、これは次のようになります...

var str = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It w as popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";

function wordWrap(text,width){
    var re = new RegExp("([\\w\\s]{" + (width - 2) + ",}?\\w)\\s?\\b", "g")
    return text.replace(re,"$1\n")
}

> wordWrap(str,40)
'Lorem Ipsum is simply dummy text of the\nprinting and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s\n, when an unknown printer took a galley of\ntype and scrambled it to make a type specimen\nbook. It has survived not only five centuries\n, but also the leap into electronic typesetting\n, remaining essentially unchanged. It w as popularised in the 1960s with the\nrelease of Letraset sheets containing Lorem\nIpsum passages, and more recently with desktop publishing\nsoftware like Aldus PageMaker including\nversions of Lorem Ipsum.'
3
cefn

私のバージョン。使用したい行区切り記号(改行やhtml BRなど)に柔軟に対応できるため、文字列ではなく行の配列を返します。

function wordWrapToStringList (text, maxLength) {
    var result = [], line = [];
    var length = 0;
    text.split(" ").forEach(function(Word) {
        if ((length + Word.length) >= maxLength) {
            result.Push(line.join(" "));
            line = []; length = 0;
        }
        length += Word.length + 1;
        line.Push(Word);
    });
    if (line.length > 0) {
        result.Push(line.join(" "));
    }
    return result;
};

行配列を文字列から文字列に変換するには:

wordWrapToStringList(textToWrap, 80).join('<br/>');

ワードラップのみを行い、長い単語を分割しないことに注意してください。おそらく最速ではありません。

正規表現と他の実装を使用して完璧なソリューションを探した後。私は自分のものを正すことにしました。それは完璧ではありませんが、私の場合はうまくいきました、あなたがすべてのテキストを大文字で持っている場合、それは正しく動作しないかもしれません。

function breakTextNicely(text, limit, breakpoints) {

      var parts = text.split(' ');
      var lines = [];
      text = parts[0];
      parts.shift();

      while (parts.length > 0) {
        var newText = `${text} ${parts[0]}`;

        if (newText.length > limit) {
          lines.Push(`${text}\n`);
          breakpoints--;

          if (breakpoints === 0) {
            lines.Push(parts.join(' '));
            break;
          } else {
                text = parts[0];
          }
        } else {
          text = newText;
        }
          parts.shift();
      }

      if (lines.length === 0) {
        return text;
      } else {
        return lines.join('');
      }
    }

    var mytext = 'this is my long text that you can break into multiple line sizes';
    console.log( breakTextNicely(mytext, 20, 3) );
1
fpauer

マルチパラグラフ入力のテキストもラップするjavabeangrinderのソリューションに基づく拡張回答は次のとおりです。

  function wordWrap(str, width, delimiter) {
    // use this on single lines of text only

    if (str.length>width) {
      var p=width
      for (; p > 0 && str[p] != ' '; p--) {
      }
      if (p > 0) {
        var left = str.substring(0, p);
        var right = str.substring(p + 1);
        return left + delimiter + wordWrap(right, width, delimiter);
      }
    }
    return str;
  }

  function multiParagraphWordWrap(str, width, delimiter) {
    // use this on multi-paragraph lines of text

    var arr = str.split(delimiter);

    for (var i = 0; i < arr.length; i++) {
        if (arr[i].length > width)
          arr[i] = wordWrap(arr[i], width, delimiter);
    }

    return arr.join(delimiter);
  }
1
Joshua Olson
function GetWrapedText(text, maxlength) {    
    var resultText = [""];
    var len = text.length;    
    if (maxlength >= len) {
        return text;
    }
    else {
        var totalStrCount = parseInt(len / maxlength);
        if (len % maxlength != 0) {
            totalStrCount++
        }

        for (var i = 0; i < totalStrCount; i++) {
            if (i == totalStrCount - 1) {
                resultText.Push(text);
            }
            else {
                var strPiece = text.substring(0, maxlength - 1);
                resultText.Push(strPiece);
                resultText.Push("<br>");
                text = text.substring(maxlength - 1, text.length);
            }
        }
    }
    return resultText.join("");
}
0
Ashutosh Pathak

正規表現にうんざりしていませんか?組み込みのArrayメソッドを使用してテキストを折り返すことができます。これを行う方法を次に示します(100希望の長さで制限:

let string = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.';

string.split(' ').map((value, index, array) => {
    if (!array.currentLineLength) {array.currentLineLength = 0}
    array.currentLineLength += value.length+1;
    if (array.currentLineLength > 100) {
        array.currentLineLength = value.length;
        return "\n" + value;
    }
    return value;
}).join(' ');

このテキストを各行でインデントしたいと思うかもしれませんか?問題ありません。これを最後のjoinの後に追加するだけです。

.split("\n").map(value => ''.padEnd(20) + value).join("\n");
0