在自动换行阿拉伯文本的 textarea 中找到“换行符”

IT技术 javascript textarea word-wrap
2021-01-21 02:31:14

我有一个文本字符串显示在文本区域(从右到左方向)中。用户可以动态调整 textarea 的大小(我为此使用 jquery)并且文本将根据需要换行。

当用户点击提交时,我将获取该文本并使用 PHP 创建一个图像,但在提交之前我想知道“换行”或“自动换行”发生的位置。

到目前为止,我所看到的所有地方都只向我展示了如何在 php 端处理换行符。我想明确表示没有换行符。我拥有的是一个 LONG 字符串,它将根据用户设置的 textarea 的宽度以不同的方式换行。

我不能使用“列”或任何其他标准宽度表示,因为我有一个非常复杂的阿拉伯字体,它实际上由许多不同宽度的字形(字符)组成。

如果有人知道访问自动换行位置的方法(如果需要,可以在 textarea 或 div 中),我真的很想知道。

我唯一的其他解决方案是实际存储(在我的数据库中)每个字符的宽度(有点乏味,因为有 600 种不同字体的 200 多个字符,总共......一些巨大的数字)。

我的希望并不高,但我想我会问。

谢谢

一世。贾马尔

6个回答

好吧,您可以使用以下函数将它们强制放入 textarea ,而不是找到换行符(这实际上是不可能的)

function ApplyLineBreaks(strTextAreaId) {
    var oTextarea = document.getElementById(strTextAreaId);
    if (oTextarea.wrap) {
        oTextarea.setAttribute("wrap", "off");
    }
    else {
        oTextarea.setAttribute("wrap", "off");
        var newArea = oTextarea.cloneNode(true);
        newArea.value = oTextarea.value;
        oTextarea.parentNode.replaceChild(newArea, oTextarea);
        oTextarea = newArea;
    }

    var strRawValue = oTextarea.value;
    oTextarea.value = "";
    var nEmptyWidth = oTextarea.scrollWidth;
    var nLastWrappingIndex = -1;
    for (var i = 0; i < strRawValue.length; i++) {
        var curChar = strRawValue.charAt(i);
        if (curChar == ' ' || curChar == '-' || curChar == '+')
            nLastWrappingIndex = i;
        oTextarea.value += curChar;
        if (oTextarea.scrollWidth > nEmptyWidth) {
            var buffer = "";
            if (nLastWrappingIndex >= 0) {
                for (var j = nLastWrappingIndex + 1; j < i; j++)
                    buffer += strRawValue.charAt(j);
                nLastWrappingIndex = -1;
            }
            buffer += curChar;
            oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length - buffer.length);
            oTextarea.value += "\n" + buffer;
        }
    }
    oTextarea.setAttribute("wrap", "");
}

此函数获取 textarea 的 ID,每当有自动换行时,它将换行符推入 textarea。在表单提交中运行该函数,您将在服务器端代码中获得带有正确换行符的文本。

已针对 IE、Chrome 和 Firefox 成功测试,请在此处自行查看:http : //jsfiddle.net/yahavbr/pH79a/1/(预览将显示新行)

@Irfan 对我来说很好用......输入“hello world,你今天好吗?希望你没事!” 它会很好地分成三行。可以发截图吗?
2021-04-05 02:31:14
此函数可能需要几秒钟才能在长文本块上运行。我在下面创建了一个使用二进制搜索的更快版本。
2021-04-05 02:31:14
大声笑...您提供的代码使用了与我相同的绝妙想法(您做得很好)但是当我测试它时,它正确地打破了第一行,然后在每个字符后添加了一个换行符(在链接 jsfiddle.net 上测试)
2021-04-06 02:31:14

这是 Shadow Wizard 解决方案的功能等效实现,它的速度要快得多,因为它使用二进制搜索而不是线性搜索来确定每行的长度:

function ApplyLineBreaks(strTextAreaId) {
    var oTextarea = document.getElementById(strTextAreaId);
    if (oTextarea.wrap) {
        oTextarea.setAttribute("wrap", "off");
    }
    else {
        oTextarea.setAttribute("wrap", "off");
        var newArea = oTextarea.cloneNode(true);
        newArea.value = oTextarea.value;
        oTextarea.parentNode.replaceChild(newArea, oTextarea);
        oTextarea = newArea;
    }

    var strRawValue = oTextarea.value;
    oTextarea.value = "";
    var nEmptyWidth = oTextarea.scrollWidth;

    function testBreak(strTest) {
        oTextarea.value = strTest;
        return oTextarea.scrollWidth > nEmptyWidth;
    }
    function findNextBreakLength(strSource, nLeft, nRight) {
        var nCurrent;
        if(typeof(nLeft) == 'undefined') {
            nLeft = 0;
            nRight = -1;
            nCurrent = 64;
        }
        else {
            if (nRight == -1)
                nCurrent = nLeft * 2;
            else if (nRight - nLeft <= 1)
                return Math.max(2, nRight);
            else
                nCurrent = nLeft + (nRight - nLeft) / 2;
        }
        var strTest = strSource.substr(0, nCurrent);
        var bLonger = testBreak(strTest);
        if(bLonger)
            nRight = nCurrent;
        else
        {
            if(nCurrent >= strSource.length)
                return null;
            nLeft = nCurrent;
        }
        return findNextBreakLength(strSource, nLeft, nRight);
    }

    var i = 0, j;
    var strNewValue = "";
    while (i < strRawValue.length) {
        var breakOffset = findNextBreakLength(strRawValue.substr(i));
        if (breakOffset === null) {
            strNewValue += strRawValue.substr(i);
            break;
        }
        var nLineLength = breakOffset - 1;
        for (j = nLineLength - 1; j >= 0; j--) {
            var curChar = strRawValue.charAt(i + j);
            if (curChar == ' ' || curChar == '-' || curChar == '+') {
                nLineLength = j + 1;
                break;
            }
        }
        strNewValue += strRawValue.substr(i, nLineLength) + "\n";
        i += nLineLength;
    }
    oTextarea.value = strNewValue;
    oTextarea.setAttribute("wrap", "");
}

更新了小提琴

这很好,虽然它似乎可以正确处理空格,但它不会在空格末尾断线,例如:“Lorem ipsum dolor , sed do incididunt ut”
2021-03-19 02:31:14
请注意,这在某些情况下不起作用。如果 textarea 的宽度和单词的结尾一样大,则该单词将出现在下一行。
2021-03-22 02:31:14
太棒了,我冒昧地添加了一个实时测试用例,并用 10 段Lorem Ipsum进行了测试,变化确实很大。荣誉!
2021-04-02 02:31:14

我认为最简单的方法是将 html 代码中 textarea 的自动换行设置为“硬”,如下所示:

<textarea id='yourTextArea' wrap='hard'></textarea>

这意味着无论您的 textarea 在哪里换行,您都会在提交时在字符串中插入一个 \n 换行符。如果您随后发现它穿过您的字符串,则可以轻松确定最初的中断位置。或者您也可以
使用 PHP 的 nl2br() 函数将这些字符转换为html 标签。

我已经测试过它不像 MDN 中记录的那样工作wrap=hard,有人知道如何利用这个有前途的属性吗?codepen.io/Unicornist/pen/xxRVrpW?editors=1010
2021-03-15 02:31:14
这是非常有用的。但是似乎不可能仅使用 javascript 检测这些换行符而不将它们发布到服务器。如果有人知道如何,请发布。
2021-04-02 02:31:14

出于某种原因,当这篇文章更新时,我从未被提醒过……昨晚,我有一个关于如何确定换行符位置的绝妙想法……我会重建字符串,并每次检查宽度,它有效,所以我来到这里分享它......发现我落后了 1 周

无论如何 2 重要的事情

  1. 您提供的代码使用了与我(您做得好)相同的绝妙想法,但是当我测试它时,它正确地打破了第一行,然后在每个字符后添加了一个换行符(在链接 jsfiddle.net 上测试)

  2. 我添加了我的代码,它使用 jquery 并使用跨度的宽度来确定何时中断首先我尝试使用 div 的宽度,但 div.width() 返回默认宽度,而不是内容的宽度。

我知道这可能不适用于所有浏览器, 所以,我恳请如果有人知道使这种方法万无一失或接近它的方法,请分享。

首先,样式是同步 textarea 和 div 之间的字体(所有属性)、设置大小以及(对于 IE)删除自动出现的任何滚动条所必需的。


    .inputArea {
      width:200px; 
      height:100px; 
      font-family:Arial; 
      font-size:12px; 
      overflow: auto; 
      border: 1px solid #cccccc;
      padding:0;
      margin:0;
    }
    .divArea {
      font-family:Arial; 
      font-size:12px;
    }
  

接下来,我包括 jquery 和我的自定义函数:

  
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js
"></script>
  <script type="text/javascript">
  $(document).ready(function() {
     $("#breakUp").click(function () {
       showLineBreaks(); 
       addLineBreaks(); 
     });

     function showLineBreaks() {
       content = $("#textEntered").val();
       //replace line breaks in content with "|" to allow for replacement below
       content = content.replace("\r\n", "
"); content = content.replace("\r", "
"); content = content.replace("\n", "
"); $("#unedited").html(content); } function addLineBreaks() { content = $("#textEntered").val(); //replace line breaks in content with "|" to allow for replacement below content = content.replace("\r\n", "|"); content = content.replace("\r", "|"); content = content.replace("\n", "|"); tempContent = ""; $("#edited").html(""); for (var i = 0; i "); } else { tempContent = $("#edited").html(); $("#edited").html(tempContent + content.charAt(i)); if ($("#edited").width() > 200) { $("#edited").html(tempContent + "
" + content.charAt(i)); } } } } }); <script>

最后,我的 html 测试页


  Enter text into the textarea below (Set to 200 px width, 100 px height)<br>
  <textarea id="textEntered" class="inputArea"></textarea>
  <br><br>
  The div below will display that text WITHOUT wrapping, BUT replacing all existing line breaks with <br><br>
  <div id="unedited"></div>
  <br>
  The following div will display that text with line breaks ADDED to fit the wrapping<br>
  <div class="divArea"><span id="edited"></span></div>  
  <br>
  <button id="breakUp">Click Here to Convert</button>

这是我计算 textarea 中每一行文本的实际行数(换行后)的示例。请注意,当滚动条开始出现时,textarea 的文本宽度会略微缩小这可能会导致对先前内容的进一步环绕,从而使先前计算的行高不正确。因此,textarea必须有CSS样式的overflow-y设置为“scroll”来强制滚动条一直显示

function get_row_wraps(txtArea){                        
    if(wrap=="off"){                                    
        var out=[];                                     
        for(var i=txtArea.split_lines.length; i>=0; --i)
            out[i]=1;                                   
        return out;                                     
    }                                                   

    var its=txtArea.value.split("\n");                        
    var newArea = txtArea.cloneNode(true);              
    newArea.hidden=true;                                
    newArea.style.visibility = "hidden";                
    txtArea.parentNode.appendChild(newArea);            

    // get single row height                            
    newArea.style.height="auto";                        
    newArea.style.overflowY="scroll";                   
    newArea.value="1\n2\n3";                            
    var unit_height=newArea.scrollHeight;               
    newArea.value="1\n2\n3\n4";                         
    var unit_height=newArea.scrollHeight-unit_height;   
    newArea.style.height=Math.round(unit_height*1.5)+"px"; // so that the scrollbar does not vanish
    newArea.value="";                                   

    // obtain row height for every line of text         
    function comp_Nrow(scroll_height){                  
        return Math.floor(scroll_height/unit_height);   
    }                                                   
    function calc_rows(txt){                            
        newArea.value+=txt;                             
        return comp_Nrow(newArea.scrollHeight);         
    }                                                   
    var out=[];                                         
    for(var i=0; i<its.length; i++)                     
        out.push(calc_rows(i==0?its[i]:("\n"+its[i]))); 
    txtArea.parentNode.removeChild(newArea);            
    for(var i=out.length-1; i>0; i--)                   
        out[i]-=out[i-1];                               
//  alert(out);                                         
    return out;                                         
}                                                       

上述函数返回 textarea 中每行文本(以“\n”分隔)的实际回绕行数。至少对于 Chrome 和 Firefox,计算是准确的。