/// <summary> /// Converts a hybrid text to CEDICT-formatted plain text (marking up hanzi+pinyin sections). /// </summary> public static string HybridToCedict(HybridText ht) { StringBuilder sb = new StringBuilder(); bool first = true; for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); if (tr is TextRunLatin) { string strRun = tr.GetPlainText(); if (!first && strRun != string.Empty && !char.IsPunctuation(strRun[0])) { sb.Append(' '); } sb.Append(strRun); } else { if (!first) { sb.Append(' '); } TextRunZho trz = tr as TextRunZho; if (!string.IsNullOrEmpty(trz.Simp)) { sb.Append(trz.Simp); } if (trz.Trad != trz.Simp && !string.IsNullOrEmpty(trz.Trad)) { sb.Append('|'); sb.Append(trz.Trad); } if (trz.Pinyin != null) { sb.Append('['); sb.Append(GetPinyinCedict(trz.Pinyin)); sb.Append(']'); } } first = false; } return(sb.ToString()); }
/// <summary> /// Returns true if display font covers all Hanzi in hybrid text; false otherwise. /// </summary> private bool areHanziCovered(HybridText ht) { if (ht.IsEmpty) { return(true); } for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); TextRunZho trJoe = tr as TextRunZho; if (trJoe == null) { continue; } if (trJoe.Simp == null) { continue; } foreach (char c in trJoe.Simp) { if (!cvr.GetCoverage(c).HasFlag(FontCoverageFlags.Simp)) { return(false); } } if (trJoe.Trad == null) { continue; } foreach (char c in trJoe.Trad) { if (!cvr.GetCoverage(c).HasFlag(FontCoverageFlags.Trad)) { return(false); } } } return(true); }
/// <summary> /// Converts a hybrid text to HTML (marking up hanzi+pinyin sections). /// </summary> public static string HybridToHtml(HybridText ht, SearchScript script) { StringBuilder sb = new StringBuilder(); bool first = true; for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); if (tr is TextRunLatin) { string strRun = tr.GetPlainText(); if (!first && strRun != string.Empty && !char.IsPunctuation(strRun[0])) { sb.Append(' '); } sb.Append(strRun); } else { if (!first) { sb.Append(' '); } TextRunZho trz = tr as TextRunZho; string hanzi1 = (script == SearchScript.Traditional) ? trz.Trad : trz.Simp; if (string.IsNullOrEmpty(hanzi1)) { hanzi1 = null; } string hanzi2 = null; if (hanzi1 != null && script == SearchScript.Both && !string.IsNullOrEmpty(trz.Trad)) { hanzi2 = trz.Trad; } if (hanzi1 != null) { hanzi1 = escape(hanzi1); } if (hanzi2 != null) { hanzi2 = escape(hanzi2); } if (hanzi1 != null || hanzi2 != null) { sb.Append(templateSenseHanziOpen); } if (hanzi1 != null) { sb.Append(hanzi1); } if (hanzi2 != null) { sb.Append(' '); sb.Append(templateBullet); sb.Append(' '); sb.Append(hanzi2); } if (hanzi1 != null || hanzi2 != null) { sb.Append(templateSenseHanziClose); } if (trz.Pinyin != null) { if (hanzi1 != null) { sb.Append(' '); } sb.Append('['); sb.Append(escape(trz.GetPinyinInOne(true))); sb.Append(']'); } } first = false; } return(sb.ToString()); }
/// <summary> /// <para>Produces unmeasured display blocks from a single hybrid text. Marks highlights, if any.</para> /// <para>Does not fill in blocks' size, but fills in everything else.</para> /// </summary> /// <param name="htxt">Hybrid text to break down into blocks and measure.</param> /// <param name="isMeta">True if this is a domain or note (displayed in italics).</param> /// <param name="hl">Highlight to show in hybrid text, or null.</param> /// <param name="blocks">List of blocks to append to.</param> /// <param name="links">List to gather links (appending to list).</param> private void makeBlocks(HybridText htxt, bool isMeta, CedictTargetHighlight hl, List <Block> blocks, List <LinkArea> links) { byte fntIdxLatin = isMeta ? fntMetaLatin : fntSenseLatin; byte fntIdxZhoSimp = isMeta ? fntMetaHanziSimp : fntSenseHanziSimp; byte fntIdxZhoTrad = isMeta ? fntMetaHanziTrad : fntSenseHanziTrad; // Go run by run for (int runIX = 0; runIX != htxt.RunCount; ++runIX) { TextRun run = htxt.GetRunAt(runIX); // Latin run: split by spaces first if (run is TextRunLatin) { string[] bySpaces = run.GetPlainText().Split(new char[] { ' ' }); // Each word: also by dash int latnPos = 0; foreach (string str in bySpaces) { string[] byDashes = splitByDash(str); // Add block for each int ofsPos = 0; foreach (string blockStr in byDashes) { Block tb = new Block { TextPos = textPool.PoolString(blockStr), FontIdx = fntIdxLatin, SpaceAfter = false, // will set this true for last block in "byDashes" }; // Does block's text intersect with highlight? if (hl != null && hl.RunIx == runIX) { int blockStart = latnPos + ofsPos; int blockEnd = blockStart + blockStr.Length; if (blockStart >= hl.HiliteStart && blockStart < hl.HiliteStart + hl.HiliteLength) { tb.Hilite = true; } else if (blockEnd > hl.HiliteStart && blockEnd <= hl.HiliteStart + hl.HiliteLength) { tb.Hilite = true; } else if (blockStart < hl.HiliteStart && blockEnd >= hl.HiliteStart + hl.HiliteLength) { tb.Hilite = true; } } blocks.Add(tb); // Keep track of position for highlight ofsPos += blockStr.Length; } // Make sure last one is followed by space Block xb = blocks[blocks.Count - 1]; xb.SpaceAfter = true; blocks[blocks.Count - 1] = xb; // Keep track of position in text - for highlights latnPos += str.Length + 1; } } // Chinese: depends on T/S/Both display mode, and on available info else { TextRunZho zhoRun = run as TextRunZho; // Chinese range is made up of: // Simplified (empty string if only traditional requested) // Separator (if both simplified and traditional are requested) // Traditional (empty string if only simplified requested) // Pinyin with accents as tone marks, in brackets (if present) string strSimp = string.Empty; if (analyzedScript != SearchScript.Traditional && zhoRun.Simp != null) { strSimp = zhoRun.Simp; } string strTrad = string.Empty; if (analyzedScript != SearchScript.Simplified && zhoRun.Trad != null) { strTrad = zhoRun.Trad; } string strPy = string.Empty; // Convert pinyin to display format (tone marks as diacritics; r5 glued) if (zhoRun.Pinyin != null) { strPy = "[" + zhoRun.GetPinyinInOne(true) + "]"; } // Create link area, with query string string strPyNumbers = string.Empty; // Pinyin with numbers as tone marks if (zhoRun.Pinyin != null) { strPyNumbers = zhoRun.GetPinyinRaw(); } LinkArea linkArea = new LinkArea(strSimp, strTrad, strPyNumbers, analyzedScript); // Block for simplified, if present if (strSimp != string.Empty) { Block tb = new Block { TextPos = textPool.PoolString(strSimp), FontIdx = fntIdxZhoSimp, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Separator if both simplified and traditional are there // AND they are different... if (strSimp != string.Empty && strTrad != string.Empty && strSimp != strTrad) { Block xb = blocks[blocks.Count - 1]; xb.StickRight = true; blocks[blocks.Count - 1] = xb; Block tb = new Block { TextPos = textPool.PoolString("•"), FontIdx = fntIdxLatin, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Traditional, if present if (strTrad != string.Empty && strTrad != strSimp) { Block tb = new Block { TextPos = textPool.PoolString(strTrad), FontIdx = fntIdxZhoTrad, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Pinyin, if present if (strPy != string.Empty) { // Split by spaces string[] pyParts = strPy.Split(new char[] { ' ' }); foreach (string pyPart in pyParts) { Block tb = new Block { TextPos = textPool.PoolString(pyPart), FontIdx = fntIdxLatin, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } } // Last part will have requested a space after. // Look ahead and if next text run is Latin and starts with punctuation, make it stick TextRunLatin nextLatinRun = null; if (runIX + 1 < htxt.RunCount) { nextLatinRun = htxt.GetRunAt(runIX + 1) as TextRunLatin; } if (nextLatinRun != null && char.IsPunctuation(nextLatinRun.GetPlainText()[0])) { Block xb = blocks[blocks.Count - 1]; xb.SpaceAfter = false; blocks[blocks.Count - 1] = xb; } // Collect link area links.Add(linkArea); } } }