2017-10-05 16 views
7

TL; DRVị trí con trỏ phù hợp cho chuỗi con sau văn bản thay thế

Tôi có chức năng thay thế văn bản, chuỗi và vị trí con trỏ (số) và tôi cần sửa vị trí (số) cho chuỗi mới tạo ra với chức năng thay thế nếu chiều dài nếu sự thay đổi chuỗi:

input and cursor position: foo ba|r text 
replacement: foo -> baz_text, bar -> quux_text 
result: baz_text qu|ux_text text 

input and cursor position: foo bar| text 
replacement: foo -> baz_text, bar -> quux_text 
result: baz_text quux_text| text 

input and cursor position: foo bar| text 
replacement: foo -> f, bar -> b 
result: f b| text 

input and cursor position: foo b|ar text 
replacement: foo -> f, bar -> b 
result: f b| text 

vấn đề là tôi có thể sử dụng chuỗi trên văn bản gốc nhưng sau đó thay thế sẽ không phù hợp với toàn bộ từ vì thế nó cần phải được thực hiện cho toàn bộ văn bản nhưng sau đó chuỗi con sẽ không khớp với phần thay thế.

Tôi cũng ổn với giải pháp con trỏ luôn ở cuối từ khi con trỏ ban đầu ở giữa từ được thay thế.

và bây giờ thực hiện của tôi, trong jQuery ga tôi có một loạt các trình định dạng chức năng trong:

$.terminal.defaults.formatters 

họ chấp nhận một chuỗi và nó sẽ trả về chuỗi mới cho nó hoạt động tốt, ngoại trừ trường hợp này:

khi Tôi có định dạng độ dài thay đổi đó nếu phá vỡ dòng lệnh, ví dụ: trình định dạng này:

$.terminal.defaults.formatters.push(function(string) { 
    return string.replace(/:smile:/g, 'a') 
       .replace(/(foo|bar|baz)/g, 'text_$1'); 
}); 

thì vị trí con trỏ sai khi lệnh li ne nhận được chuỗi mới.

Tôi đã cố gắng khắc phục điều này nhưng nó không làm việc như mong đợi, nội bộ của giao diện thiết bị đầu cuối như thế này,

khi tôi thay đổi position Tôi đóng thùng một biến khác formatted_position đó là sử dụng trong dòng lệnh để hiển thị con trỏ. để có được giá trị mà tôi sử dụng này:

formatted_position = position; 
var string = formatting(command); 
var len = $.terminal.length(string); 
var command_len = $.terminal.length(command); 
if (len !== command_len) { 
    var orig_sub = $.terminal.substring(command, 0, position); 
    var orig_len = $.terminal.length(orig_sub); 
    var formatted = formatting(orig_sub); 
    var formatted_len = $.terminal.length(formatted); 
    if (orig_len > formatted_len) { 
     // if formatting make substring - (text before cursor) 
     // shorter then subtract the difference 
     formatted_position -= orig_len - formatted_len; 
    } else if (orig_len < formatted_len) { 
     // if the formatted string is longer add difference 
     formatted_position += formatted_len - orig_len; 
    } 
} 

if (formatted_position > len) { 
    formatted_position = len; 
} else if (formatted_position < 0) { 
    formatted_position = 0; 
} 

$ .terminal.substring và $ .terminal.length là hàm helper được định dạng thiết bị đầu cuối nhận biết (văn bản trông giống như [[b;#fff;]hello] này) nếu bạn sẽ viết giải pháp bạn có thể sử dụng văn bản bình thường và sử dụng các phương thức chuỗi.

vấn đề là khi tôi di chuyển con trỏ ở giữa các từ có nghĩa là thay đổi

nó loại công việc khi văn bản dài hơn, nhưng đối với chuỗi ngắn nhảy con trỏ sang bên phải khi văn bản là trong giữa từ đã được thay thế.

Tôi đã cố gắng khắc phục điều này cũng sử dụng mã này:

function find_diff(callback) { 
    var start = position === 0 ? 0 : position - 1; 
    for (var i = start; i < command_len; ++i) { 
     var substr = $.terminal.substring(command, 0, i); 
     var next_substr = $.terminal.substring(command, 0, i + 1); 
     var formatted = formatting(next_substr); 
     var substr_len = $.terminal.length(substr); 
     var formatted_len = $.terminal.length(formatted); 
     var diff = Math.abs(substr_len - formatted_len); 
     if (diff > 1) { 
      return diff; 
     } 
    } 
    return 0; 
} 

... 

} else if (len < command_len) { 
    formatted_position -= find_diff(); 
} else if (len > command_len) { 
    formatted_position += find_diff(); 
} 

nhưng điều này tôi nghĩ rằng làm cho nó thậm chí tệ hơn bởi vì nó tìm diff khi con trỏ là trước hoặc ở giữa chữ thay thế và nó nên chỉ tìm thấy khác khi con trỏ ở giữa từ được thay thế.

Bạn có thể xem kết quả của những nỗ lực của tôi trong codepen https://codepen.io/jcubic/pen/qPVMPg?editors=0110 này (cho phép gõ biểu tượng cảm xúc và foo bar baz được thay thế bởi text_$1)

CẬP NHẬT:

tôi đã làm cho nó loại làm việc với mã này:

// --------------------------------------------------------------------- 
    // :: functions used to calculate position of cursor when formatting 
    // :: change length of output text like with emoji demo 
    // --------------------------------------------------------------------- 
    function split(formatted, normal) { 
     function longer(str) { 
      return found && length(str) > length(found) || !found; 
     } 
     var formatted_len = $.terminal.length(formatted); 
     var normal_len = $.terminal.length(normal); 
     var found; 
     for (var i = normal_len; i > 1; i--) { 
      var test_normal = $.terminal.substring(normal, 0, i); 
      var formatted_normal = formatting(test_normal); 
      for (var j = formatted_len; j > 1; j--) { 
       var test_formatted = $.terminal.substring(formatted, 0, j); 
       if (test_formatted === formatted_normal && 
        longer(test_normal)) { 
        found = test_normal; 
       } 
      } 
     } 
     return found || ''; 
    } 
    // --------------------------------------------------------------------- 
    // :: return index after next word that got replaced by formatting 
    // :: and change length of text 
    // --------------------------------------------------------------------- 
    function index_after_formatting(position) { 
     var start = position === 0 ? 0 : position - 1; 
     var command_len = $.terminal.length(command); 
     for (var i = start; i < command_len; ++i) { 
      var substr = $.terminal.substring(command, 0, i); 
      var next_substr = $.terminal.substring(command, 0, i + 1); 
      var formatted_substr = formatting(substr); 
      var formatted_next = formatting(next_substr); 
      var substr_len = length(formatted_substr); 
      var next_len = length(formatted_next); 
      var test_diff = Math.abs(next_len - substr_len); 
      if (test_diff > 1) { 
       return i; 
      } 
     } 
    } 
    // --------------------------------------------------------------------- 
    // :: main function that return corrected cursor position on display 
    // :: if cursor is in the middle of the word that is shorter the before 
    // :: applying formatting then the corrected position is after the word 
    // :: so it stay in place when you move real cursor in the middle 
    // :: of the word 
    // --------------------------------------------------------------------- 
    function get_formatted_position(position) { 
     var formatted_position = position; 
     var string = formatting(command); 
     var len = $.terminal.length(string); 
     var command_len = $.terminal.length(command); 
     if (len !== command_len) { 
      var orig_sub = $.terminal.substring(command, 0, position); 
      var orig_len = $.terminal.length(orig_sub); 
      var sub = formatting(orig_sub); 
      var sub_len = $.terminal.length(sub); 
      var diff = Math.abs(orig_len - sub_len); 
      if (false && orig_len > sub_len) { 
       formatted_position -= diff; 
      } else if (false && orig_len < sub_len) { 
       formatted_position += diff; 
      } else { 
       var index = index_after_formatting(position); 
       var to_end = $.terminal.substring(command, 0, index + 1); 
       //formatted_position -= length(to_end) - orig_len; 
       formatted_position -= orig_len - sub_len; 
       if (orig_sub && orig_sub !== to_end) { 
        var formatted_to_end = formatting(to_end); 
        var common = split(formatted_to_end, orig_sub); 
        var re = new RegExp('^' + $.terminal.escape_regex(common)); 
        var to_end_rest = to_end.replace(re, ''); 
        var to_end_rest_len = length(formatting(to_end_rest)); 
        if (common orig_sub !== common) { 
         var commnon_len = length(formatting(common)); 
         formatted_position = commnon_len + to_end_rest_len; 
        } 
       } 
      } 
      if (formatted_position > len) { 
       formatted_position = len; 
      } else if (formatted_position < 0) { 
       formatted_position = 0; 
      } 
     } 
     return formatted_position; 
    } 

nó không hoạt động cho một trường hợp khi bạn nhập biểu tượng cảm xúc làm ký tự đầu tiên và con trỏ ở giữa: smile: word. Cách sửa hàm get_formatted_position để có vị trí cố định chính xác sau khi thay thế?

CẬP NHẬT: Tôi đã hỏi câu hỏi khác nhau và đơn giản và có những giải pháp sử dụng chức năng trackingReplace chấp nhận regex và chuỗi, vì vậy tôi đã thay đổi API cho trình định dạng để chấp nhận mảng với regex và chuỗi dọc theo chức năng Correct substring position after replacement

+1

Bạn có chắc chắn, di chuyển con trỏ vào từ được thay thế không? Đối với tôi nó có vẻ khá khó hiểu. Tôi sẽ nhìn vào Word, hoặc tài liệu google nếu họ không di chuyển nó ở đầu hoặc cuối. – Akxe

+0

@Akxe đó là trường hợp hoàn toàn khác so với từ hoặc tài liệu google, bởi vì văn bản được thay thế trong khi bạn nhập không khi bạn thay thế văn bản như trong chức năng tìm kiếm/thay thế. Và nó trông rất lạ khi bạn không thay đổi vị trí bởi vì bạn có thể kết thúc phần cuối của văn bản có độ dài là 10 và văn bản thay thế là 3 và bạn nhận được vị trí của 10 nó phải là 3. – jcubic

+0

Ý tôi là, nếu bạn thay thế từ con trỏ của bạn hiện đang ở bên trong, sau đó có thể tốt hơn là đặt con trỏ ở phía trước hoặc sau từ mới được thay thế. Và Word chắc chắn có tùy chọn để thay thế. – Akxe

Trả lời

1

Vì vậy, tôi đã có thể hoàn thành nhiệm vụ đã cho, tuy nhiên tôi đã không thể thực hiện nó vào thư viện vì tôi không chắc chắn làm thế nào để thực hiện nhiều thứ ở đó.

Tôi đã tạo trong javascript vanilla để không bị trục trặc trong khi triển khai vào thư viện. Tập lệnh chủ yếu phụ thuộc vào các thuộc tính selectionStartselectionEnd có sẵn trên các yếu tố văn bản, đầu vào hoặc tương tự. Sau khi tất cả thay thế được thực hiện, lựa chọn mới được đặt thành vùng văn bản sử dụng phương pháp setSelectionRange.

// sel = [selectionStart, selectionEnd] 
function updateSelection(sel, replaceStart, oldLength, newLength){ 
    var orig = sel.map(a => a) 
    var diff = newLength - oldLength 
    var replaceEnd = replaceStart + oldLength 
    if(replaceEnd <= sel[0]){ 
     // Replacement occurs before selection 
     sel[0] += diff 
     sel[1] += diff 
     console.log('Replacement occurs before selection', orig, sel) 
    }else if(replaceStart <= sel[0]){ 
     // Replacement starts before selection 
     if(replaceEnd >= sel[1]){ 
      // and ends after selection 
      sel[1] += diff 
     }else{ 
      // and ends in selection 
     } 
     console.log('Replacement starts before selection', orig, sel) 
    }else if(replaceStart <= sel[1]){ 
     // Replacement starts in selection 
     if(replaceEnd < sel[1]){ 
      // and ends in seledtion 
     }else{ 
      // and ends after selection 
      sel[1] += diff 
     } 
     console.log('Replacement starts in selection', orig, sel) 
    } 
} 

Đây là toàn bộ bản demo: codepen.

PS: Từ quan sát của tôi, định dạng tập lệnh chạy theo cách thường xuyên.

+0

Xin lỗi có lẽ tôi không đủ rõ ràng, nhưng tôi không muốn giữ con trỏ cho văn bản đã chọn trong văn bản nhưng tôi cần chuỗi này cho chuỗi bình thường (tôi không có bất kỳ lựa chọn nào) và con trỏ chỉ là số không phải là con trỏ văn bản thực. – jcubic

+0

Tôi có textarea trong terminal nhưng nó cần phải có văn bản gốc chứ không phải thay thế, và một điều nữa tôi có một chức năng như tôi đã đề cập, làm tất cả thay thế tôi không thể lặp qua các phím như trong mã của bạn làm nhiều từ không phải là một duy nhất để mã của bạn sẽ phá vỡ khi bạn làm điều này 'string = string.replace (new RegExp (toRelpace.replace (/ ([()])/g, '\\ $ 1'), 'g') , replaceWith) ' – jcubic

+0

Vì vậy, bạn cần văn bản được định dạng cũng như văn bản gốc? Việc lựa chọn có thể được sử dụng chủ yếu là không thay đổi ngay cả khi bạn không sử dụng bắt đầu và kết thúc, chỉ cần tưởng tượng bắt đầu và kết thúc là cùng một số. Và regexps, bạn có chúng riêng biệt, bạn chỉ cần concat chúng trong mã của bạn. – Akxe

Các vấn đề liên quan