utf-8編碼的字元串怎麼檢測它實際渲染出來的長度,如果超過長度就用省略號補上到末尾?

網上的方法大都是只硬性地數字元串的字元個數,漢字算2,英文算1,但是我希望能支持其他文字,有好的方法提供嗎?


我來回答這個問題吧(我是李阿玲二號機)。你應該如下操作:

  1. 將UTF-8編碼轉換為內部編碼,化整為uint16_t或者uint32_t。
  2. 確定對應文本的字體,如果一個字體足夠,那就用一個;如果一個字體不夠,用多個(這叫fallback);一個字形不夠用,比如要用中日兩種漢字字形,得用一個套組(這個叫fontset)。
  3. 確定文本的斷行模型(這叫linebreak),如果存在字串形式的詞,則還需要考慮切詞的演算法(這叫hyphenation)。斷行模型,你可以選擇Unicode中欽點的方法,也可以考慮更抽象的Box-Glue-Penalty模型。切詞演算法,你可以選擇trie或者hash來實現,用現成的也可以,比如libhnj和OpenOffice中的擴展。
  4. 確定是否存在複雜語言文本,比如東南亞諸國語言,南亞大陸諸國語言,阿拉伯世界諸國語言。如果有,那麼你可能要做bidirection處理,可能要做text轉換為grapheme塊進行內部調整翻轉拼接。當然還有蒙文,滿文這類方向比較獨特的語言,這要在處理的時候加h和v方向兩個語義,這就變成了四個維度上的操作了,但是我還沒看過這麼洋氣的遊戲呢。
  5. 要不要用OpenType的feature,要用什麼script什麼language的什麼feature?這涉及到如何和2提到的對應。
  6. 那麼接下來,都確定了,那麼你可以把這一大串uint32_t的數轉換為glyph了。這裡的glyph要帶著位置信息,通常的漢字和latin諸語用一維夠用,其他語言你必須要用二維進行描述(通常都是浮點數,如果你習慣於寫自己的數值系統,用fixed point數也不是不可以)。那麼這樣就變成一個unicode char string轉化為glyph string的過程了。通常,這個時候就可以通過遍歷得到最終的長度。這個時候該切掉甲乙丙丁切甲乙丙丁,加省略號吧。
  7. 如果你想加一些裝飾性的東西,那麼你在轉化為內部編碼的時候就必須定義一些節點性質的數據結構,其中可以指定顏色,字體大小,基線調整大小,是否畫下劃線,是否要加背景紋理。這些要在第6步之後進行。
  8. 如果你要輸出為最終的格式,比如圖片,那麼你可能需要對PostScript或者TrueType作處理轉化為點陣圖,很好說,這都有FreeType給你做了。
  9. 給李阿玲捐錢。


給Belleve的回答補充一點。

那個複雜的排版過程,還特么一半是靠排版引擎,一半是靠字體內建的索引表實現的……所以……你不是憑空寫個代碼出來就行了的,還要聽字體的意見,但是你的決定權也是很重要的……


中英文的話你有字體就可以讀尺寸(hmtx/CFF)算出來。但是你要支持其他語種……

這是 Devanagari 的排版過程,經過了大量的符號替換、順序重排,來,你知道具體的規則么?

烏爾都語使用的 Nastaliq 式阿拉伯文甚至是斜的


首先你要識別那是什麼文字,其次識別該文字的渲染順序(bid嵌套),然後看哪幾個unicode字元會在渲染的時候合併成一個字,最後挨個計算過去,看看什麼時候放不下了,把最後面的儘可能少的幾個字(不是字元)換成「...」

我建議你使用unity自帶的功能來做,因為這些事情在每個系統上都做爛了,你為什麼要自己來。


每個文本渲染引擎都會提供這樣的功能。Unity裡面可以用這個:

http://docs.unity3d.com/ScriptReference/GUIStyle.CalcSize.html


貌似不需要那麼複雜。你只是要獲取渲染後的長度是吧,在 WPF 里可以這樣寫:

var tb = new TextBlock()
{
FontFamily = new FontFamily("宋體"),
FontSize = 16,
TextWrapping = TextWrapping.NoWrap, //不換行
Text = "字元串balabalabala...."
};

tb.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

tb.ActualWidth 就是長度。

供參考。


渲染的長度,那還和字體字型大小字型有關啊~~你到底要渲染效果還是只是要算一下字元串佔位數量?

拋開字體的問題,單說不同語言的文字,根據unicode碼錶,所有支持的語言,你基本總結一下你需要的文字每個字元的寬度,比如你說的英文1,中文2,還有其他的。

具體判斷語言就按照unicode碼錶來,比如:

Armenia:0x0530, 0x058f

Arabic:0x0600, 0x06FF;0x0750, 0x077F;0xFB50, 0xFDFF;0xFE70, 0xFEFF

中日韓漢字:0x4E00, 0x9FBF;0x3400, 0x4DBF;0x20000, 0x2A6DF;0xF900, 0xFAFF;0x2F800, 0x2FA1F;


關鍵不在於UTF-8編碼,還要考慮渲染採用的字體、字型大小、樣式等參數。

可以借鑒Qt裡面QFontMetrics的實現:

QFontMetrics functions calculate the size of characters and strings for a given font.

http://doc.qt.io/qt-4.8/qfontmetrics.html


unity有textgenerator

文檔里說怎麼獲取字元串渲染以後的長度


渲染長度本身是和編碼沒有關係的,編碼只是說什麼字對應的計算機內存數據是什麼,渲染是由字體文件決定的。

我知道的字體渲染在遊戲領域用的比較多的是freetype,它的功能就是給定一個字體文件和一個編碼,然後可以獲得一個8位的點陣圖,然後再由引擎把這個點陣圖渲染到屏幕上,所以渲染的寬度是由你的字體文件,和字型大小決定的,就是你這個點陣圖的size。

回到問題本身,給定一段文字

foreach utf8編碼

獲取點陣圖;

渲染;

寬度累加;

if 超過規定長度,

補充渲染「...」

break;

end

end

希望有幫助


推薦閱讀:

如何幫助重義氣的男友找到更優秀的合伙人?
如何學好 Unity?
独立游戏的开发过程中如何准确的确定构思的元素是否有趣?
用Unity引擎開發遊戲,如何提升編程能力?
Unity開發怎麼優化大量物體的物理碰撞而產生的FPS等參數急劇下降?

TAG:Unity遊戲引擎 | C# | UTF-8 | Lua | 計算機圖形學 |