2014-06-19 27 views
5

Tôi đang làm việc trên một trình mô phỏng văn bản/thiết bị đầu cuối đơn giản (tương tự như plugin thiết bị đầu cuối JQuery, nhưng không có các công cụ RPC và chức năng cửa sổ). Mỗi dòng của màn hình là một hàng của bảng (một chuỗi HTML) và lệnh in có thể chèn văn bản với một số thuộc tính (ví dụ: màu nền trước và màu nền). Mỗi văn bản được in được bao quanh bởi một khoảng có thuộc tính kiểu, ví dụ:Nhận các thuộc tính kèm theo thẻ trong chuỗi HTML

<span style="color:#000000;background-color:#111111">A</span><span style="color:#222222;background-color:#333333>BC</span> 

Điều này làm việc tốt. Bây giờ tôi muốn thêm một chức năng mang lại cho tôi tất cả các thuộc tính của một nhân vật ở một vị trí màn hình nhất định, trong dòng trên, ký tự ở vị trí 0 (A) có màu # 000000. Vì vậy, tôi phải tính các ký tự không thuộc về thẻ span và nhận được các kiểu trước đó trước. Giải pháp dễ bị lỗi đầu tiên của tôi là:

function getAttr(line, position) { 
    var result = {foreground:'', background:''}, 
     ch = '', i, j = -1, tag = false; 

    // Count characters 
    for (i = 0; i < line.length && j < position; i++) { 
     ch = line.charAt(i); 

     if (ch == '<') { 
      tag = true; 
     } 

     if (ch == '>') { 
      tag = false; 
     } 
     else if (!tag) { 
      j++; 
     } 
    } 

    i--; 

    // Find styles 
    while (i > 0 && line.charAt(i) != '<') { 
     if (line.substr(i, 6) == 'color:') { 
      result.foreground = line.substr(i + 6, 7); 
     } 
     if (line.substr(i, 17) == 'background-color:') { 
      result.background = line.substr(i + 17, 7); 
     } 
     i--; 
    } 

    return result; 
} 

Có giải pháp đơn giản hơn mà không tính các ký tự (có thể là JQuery hoặc regex) không?

Điều này tương tự như Get parent element of a selected text nhưng tôi không cần lựa chọn, chỉ là chỉ mục ký tự.

Trả lời

0

Tôi muốn bỏ công việc phân tích cú pháp HTML thành trình duyệt và chỉ sử dụng cây DOM kết quả. Dưới đây là một số mã giả bạn có thể sử dụng dựa trên ý tưởng sử dụng cây DOM:

function getAttr(lineNumber, position) { 
    var lineDom = getDOMContainerForLineNumber(lineNumber); 
    var current = 0; // the current character position 

    function getAttrRec(elems, foreground, background) { 
    for(elem in elems) { 
     if(elem is <span>) { 
     var res = getAttrRec(elem.children, elem.foregroundColor, elem.backgroundColor); 
     if(res != null) 
      return res; 
     } else if(elem is TEXT) { 
     current += elem.textLength; 
     if(current >= position) 
      return {foreground: foreground, background: background}; 
     } 
    } 
    return null; 
    } 

    return getAttrRec(lineDom.children, black, black); 
} 

Đây chỉ là một bản phác thảo rất thô. Đặc biệt bạn sẽ phải chú ý đến những khoảng trắng - chúng bị tước đi khá nhiều bởi các trình duyệt. Vì vậy, trực tiếp dựa vào chiều dài văn bản có thể không hoạt động trong trường hợp của bạn. Ngoài ra, bạn có thể muốn xử lý trường hợp thẻ span không chứa thông tin về màu nền trước hoặc màu nền.

1

Một cách có thể để xử lý việc xây dựng cấu trúc dữ liệu cho phép bạn lập chỉ mục mỗi dòng và nhận được ký tự và các kiểu được liên kết có thể được thực hiện bằng đoạn mã sau cho mỗi dòng. Điều này giả định đánh dấu bạn đang tạo cho HTML hiển thị ở trên là khá ổn định cũng như (bạn có thể giải thích cho các biến thể trong regex nếu cần):

var tagre = /\<span style="([^"]+)"\>([A-Za-z]+)\<\/span\>/ig, 
    s = '<span style="color:#000000;background-color:#111111">A</span><span style="color:#222222;background-color:#333333">BC</span>'; 

var matches, 
    positions = []; 

while (matches = tagre.exec(s)) { 
    var len = matches[2].length, 
     chars = matches[2], 
     styles = {}; 

    matches[1].split(';').forEach(function(o) { 
     var _s = o.split(':'), 
      key = _s[0], 
      val = _s[1]; 
     styles[key] = val; 
    }); 

    for (var i=0; i < len; i++) { 
     var char = chars[i]; 
     positions.push({ 'char': char, 'styles': styles }); 
    } 
} 
console.log("positions=%o", positions); 

Điều này sẽ cung cấp cho bạn một mảng cho mỗi dòng đó trông như thế như sau:

[ 
    { char: 'A', 
    styles: { 'background-color': '#111111', 'color': '#000000' } 
    }, 
    { char: 'B', 
    styles: { 'background-color': '#333333', 'color': '#222222' } 
    }, 
    { char: 'C', 
    styles: { 'background-color': '#333333', 'color': '#222222' } 
    } 
] 

Điều đó sẽ cho phép bạn lập chỉ mục vào từng dòng theo vị trí ký tự nguyên và nhận ký tự ở vị trí đó cùng với kiểu được liên kết làm đối tượng.

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