실행하는 소스 보기
소스 내려받기1import std.io2import std.typeset {3 BreakCluster, BreakPolicy, BreakMode, KinsokuRules, BreakOpportunity, Paragraph, Item,4 Box, Penalty, BreakRule, DistanceGrid, CostModel, LineGeometry, JustificationPolicy,5 JustificationMode, KnuthPlassPolicy, ParagraphPlan, PlanLine, classifyBreaks,6 breakParagraph,7}89// HAZE adapter. First stdin line is width in millipoints, followed by the sentence.10let hazeInput = io.readStdin().split("\n")11let 줄너비 = hazeInput[0].toInt() ?? 1000001213// 너비는 1000분의 1포인트 단위입니다. 한글은 10포인트, 빈칸은 2.5포인트로 둡니다.14function 글자(낱자: string) -> BreakCluster {15 BreakCluster { text: 낱자, advance: if 낱자 == " " { 2500 } else { 10000 }, trackingAfter: 0 }16}1718// 유니코드 줄바꿈 규칙(UAX #14)에 한국어 금칙(KLReq)을 더합니다. 줄에 들어가는 낱말은 쪼개지 않습니다.19function 한국어규칙(글자들: Array<BreakCluster>) -> BreakPolicy {20 BreakPolicy {21 mode: BreakMode.Word, rules: KinsokuRules.Unicode16Ko,22 forbidBefore: [], forbidAfter: [], boundaryAllowed: 글자들.map((c: BreakCluster) => true),23 generatedHyphenEnds: [], protectFittingLatin: false, preserveShortWords: false,24 narrowestWordTarget: 줄너비, bodyWordTarget: 줄너비25 }26}2728// 글자마다 상자 하나, 줄을 나눌 수 있는 자리마다 벌점 0을 둡니다. 마지막 자리에서는 반드시 줄을 끝냅니다.29function 문단(글자들: Array<BreakCluster>, 자리들: Array<BreakOpportunity>) -> Paragraph {30 let mut 항목: Array<Item> = []31 for 번호 in 0..<글자들.length {32 let 낱자 = 글자들[번호]33 항목.push(Item.BoxItem(Box { unitIndex: 번호, text: 낱자.text, width: 낱자.advance, trackingAfter: 0 }))34 }35 for 자리 in 자리들 {36 let 끝 = 자리.unitEnd == 글자들.length37 항목.push(Item.PenaltyItem(Penalty {38 unitEnd: 자리.unitEnd, width: 0, kind: 자리.kind, flagged: false,39 rule: if 끝 { BreakRule.Forced } else { BreakRule.Allowed(0) }40 }))41 }42 Paragraph {43 grid: DistanceGrid.MilliPoint, items: 항목, costModel: CostModel.FixedPoint,44 geometry: LineGeometry { bodyTarget: 줄너비, firstTarget: 줄너비, dropCapSpan: 0, dropCapInset: 0 },45 justification: JustificationPolicy {46 mode: JustificationMode.Unjustified, minGapCount: 0, minLineWidthRatioM: 0,47 minFinalLineWidthRatioM: None, maxAdjustment: 0, maxGapAdjustment: 0, maxGapRatioR: 0,48 latinSpacing: None, cjkStretchRatio: 0.049 },50 knuthPlass: KnuthPlassPolicy {51 toleranceR: 0, linePenalty: 0, fitnessDemerit: 0, flaggedDemerit: 0, finalFlaggedDemerit: 052 }53 }54}5556// 줄마다 글자를 이어 붙이고 줄 끝 빈칸은 뺍니다.57function 줄글(글자들: Array<BreakCluster>, 계획: ParagraphPlan) -> string {58 계획.lines59 .map((줄: PlanLine) => 글자들.slice(줄.start, 줄.trimmedEndExclusive).map((c: BreakCluster) => c.text).join(""))60 .join("\n")61}6263let 문장 = hazeInput.slice(1, hazeInput.length).join("\n")64let 글자들 = 문장.scalars().map(글자)65let 결과 = classifyBreaks(글자들, 한국어규칙(글자들))66 .flatMap((자리들: Array<BreakOpportunity>) => breakParagraph(문단(글자들, 자리들)))67match 결과 {68 case Ok(나눔) => {69 // HAZE adapter. Return actual plan metrics and scalar boundaries.70 io.writeLine("optimized {나눔.optimized.lines.length} {나눔.optimized.totalCost}")71 for 줄 in 나눔.optimized.lines {72 io.writeLine("{줄.start} {줄.trimmedEndExclusive} {줄.trimmedTextWidth}")73 }74 io.writeLine("greedy {나눔.greedy.lines.length} {나눔.greedy.totalCost}")75 for 줄 in 나눔.greedy.lines {76 io.writeLine("{줄.start} {줄.trimmedEndExclusive} {줄.trimmedTextWidth}")77 }78 }79 case Err(오류) => io.writeLine("{오류}")80}