slist.tin 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. #nop vim: set filetype=tt:;
  2. /*
  3. 本文件属于 PaoTin++ 的一部分。
  4. PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp <danzipao@gmail.com>) 享有并保留一切法律权利
  5. 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。
  6. */
  7. #nop 本文件是 xtintin 的一部分,实现了一些字符串列表处理函数;
  8. ///=== {
  9. ///// 字符串列表处理函数:
  10. //
  11. // #@ slist.FromList <列表>
  12. // 将列表转换为字符串列表。
  13. // <119>注意<299>,由于 TinTin++ 自身语法的缺陷,字符串列表的第一个元素只能是
  14. // 简单字符串,不能是列表、字符串列表、表格,其余元素不受此限制。
  15. // };
  16. #func {slist.FromList} {
  17. #local list {%0};
  18. #if { &list[] == 0 } {
  19. #return {};
  20. };
  21. #local output {};
  22. #local idx {};
  23. #loop {1} {&list[]} {idx} {
  24. #local elem {$list[$idx]};
  25. #local complex 0;
  26. #local isSlist 0;
  27. #if { @slist.Size{$elem} > 1 } {
  28. #local isSlist 1;
  29. };
  30. #if { $isSlist || {$elem} == {{\{.*\}}} } {
  31. #local complex 1;
  32. };
  33. #if { $idx == 1 } {
  34. #if { $complex } {
  35. #line sub {var;escapes;secure} #cat output {$elem};
  36. };
  37. #else {
  38. #cat output {$elem};
  39. };
  40. };
  41. #elseif { $complex } {
  42. #cat output {;{$elem}};
  43. };
  44. #else {
  45. #cat output {;$elem};
  46. };
  47. };
  48. #return {$output};
  49. };
  50. ///=== {
  51. // #@ slist.Size <字符串列表>
  52. // 计算字符串列表中一共有几项内容。
  53. // };
  54. #func {slist.Size} {
  55. #local l {};
  56. #list l create {%0};
  57. #list l size result;
  58. };
  59. ///=== {
  60. // #@ slist.Append <字符串列表> <字符串>
  61. // 往字符串列表里追加新内容。
  62. // <119>注意<299>,由于 TinTin++ 自身语法的缺陷,字符串列表的第一个元素只能是
  63. // 简单字符串,不能是列表、字符串列表、表格,其余元素不受此限制。
  64. //
  65. // EXAMPLE: \@slist.Append{{a;b;c};X}
  66. // RESULT: {a;b;c;X}
  67. //
  68. // EXAMPLE: \@slist.Append{{a;b;c};{X;Y}}
  69. // RESULT: {a;b;c;{X;Y}}
  70. //
  71. // EXAMPLE: \@slist.Append{{a;b;c};{{X}{xxx}{Y}{yyy}}}
  72. // RESULT: {a;b;c;{{X}{xxx}{Y}{yyy}}}
  73. //
  74. // EXAMPLE: \@slist.Append{{};X}
  75. // RESULT: {X}
  76. // };
  77. #func {slist.Append} {
  78. #local list {%1};
  79. #local str {%2};
  80. #if { {$list} === {} } {
  81. #if { {$str} != {} } {
  82. #line sub {var;secure} #cat list $str;
  83. };
  84. };
  85. #elseif { {$str} == {%*;%*} } {
  86. #cat list {;{$str}};
  87. };
  88. #elseif { {$str} == {\{%*\}} } {
  89. #cat list {;{$str}};
  90. };
  91. #else {
  92. #cat list {;$str};
  93. };
  94. #return {$list};
  95. };
  96. ///=== {
  97. // #@ slist.Insert <字符串列表> <位置> <字符串>
  98. // 在字符串列表的指定位置插入新内容,元素位置从 1 开始计。
  99. // <119>注意<299>,由于 TinTin++ 自身语法的缺陷,字符串列表的第一个元素只能是
  100. // 简单字符串,不能是列表、字符串列表、表格,其余元素不受此限制。
  101. // };
  102. #func {slist.Insert} {
  103. #local list {%1};
  104. #local index {%2};
  105. #local str {%3};
  106. #local l {};
  107. #list l create {%1};
  108. #local l {@list.Extend{{$l};@math.Eval{$index - 1}}};
  109. #if { $index > &l[] } {
  110. #list l add {{$str}};
  111. };
  112. #else {
  113. #if { $index == 1 } {
  114. #line sub {var;secure} #format str {%s} $str;
  115. };
  116. #list l insert {$index} {$str};
  117. };
  118. #return {@slist.FromList{$l}};
  119. };
  120. ///=== {
  121. // #@ slist.Remove <字符串列表> <位置> [<N>]
  122. // 删除字符串列表中,从指定位置开始的连续 N 个元素,元素位置从 1 开始计。
  123. // N 为可选值,默认为 1。
  124. // };
  125. #func {slist.Remove} {
  126. #local index {%2};
  127. #local amount {@defaultNum{%3;1}};
  128. #local l {};
  129. #list l create {%1};
  130. #list l delete {$index} {$amount};
  131. #return {@slist.FromList{$l}};
  132. };
  133. ///=== {
  134. // #@ slist.DictTranslate <字符串列表> <字典>
  135. // 通过字典对字符串列表进行翻译。
  136. // 返回新的字符串列表。
  137. // };
  138. #func {slist.DictTranslate} {
  139. #local slist {%1};
  140. #local dict {%2};
  141. #local l {};
  142. #local elem {};
  143. #foreach {$slist} {elem} {
  144. #if { "$elem" !== "" } {
  145. #if { &dict[$elem] > 0 } {
  146. #local new {$dict[$elem]};
  147. #if { "$new" === "" } {
  148. #continue;
  149. };
  150. #else {
  151. #list l add {{$new}};
  152. };
  153. };
  154. };
  155. };
  156. #list l collapse {;};
  157. #return {$l};
  158. };
  159. ///=== {
  160. // #@ slist.Translate <字符串列表> <旧元素列表> <新元素列表>
  161. // 对字符串列表进行翻译。将字符串列表中的旧元素用相对应的新元素替代。
  162. // 返回新的字符串列表。
  163. // };
  164. #func {slist.Translate} {
  165. #local slist {%1};
  166. #local keys {%2};
  167. #local values {%3};
  168. #list values create {$values};
  169. #local dict {};
  170. #local idx {0};
  171. #local key {};
  172. #foreach {$keys} {key} {
  173. #math idx {$idx + 1};
  174. #local value {$values[+$idx]};
  175. #local dict[$key] {$value};
  176. };
  177. #return {@slist.DictTranslate{{$slist};{$dict}}};
  178. };
  179. ///=== {
  180. // #@ slist.Drop <字符串列表> <元素列表>
  181. // 从字符串列表中删除在元素列表中出现过的元素。
  182. // 返回新的字符串列表。
  183. // };
  184. #func {slist.Drop} {
  185. #return {@slist.Translate{{%1};{%2}}};
  186. };
  187. ///=== {
  188. // #@ slist.IndexOf <字符串列表> <字符串>
  189. // 从字符串列表中查找某个字符串,并返回其位置(从 1 开始计),0 表示没找到。
  190. // };
  191. #func {slist.IndexOf} {
  192. #local list {%1};
  193. #local str {%2};
  194. #local idx {0};
  195. #local elem {};
  196. #foreach {$list} {elem} {
  197. #math idx {$idx + 1};
  198. #if { {$elem} === {$str} } {
  199. #return $idx;
  200. };
  201. };
  202. #return 0;
  203. };
  204. ///=== {
  205. // #@ slist.Find <字符串列表> <正则表达式>
  206. // 从字符串列表中按顺序查找某个模式,并返回第一个符合模式的元素的位置(从 1 开始计),0 表示没找到。
  207. // };
  208. #func {slist.Find} {
  209. #local list {%1};
  210. #local str {%2};
  211. #local idx {0};
  212. #local elem {};
  213. #foreach {$list} {elem} {
  214. #math idx {$idx + 1};
  215. #if { "$elem" == "$str" } {
  216. #return $idx;
  217. };
  218. };
  219. #return 0;
  220. };
  221. ///=== {
  222. // #@ slist.Filter <字符串列表> <正则表达式>
  223. // 遍历字符串列表,根据正则表达式过滤元素并生成新字符串列表。如果条件为真则收集,否则跳过。
  224. // 本函数与 select 作用类似。但 select 支持条件表达式,可进行逻辑运算,本函数仅支持模式匹配。
  225. // };
  226. #func {slist.Filter} {
  227. #local list {%1};
  228. #local regex {%2};
  229. #local output {};
  230. #local elem {};
  231. #foreach {$list} {elem} {
  232. #if { "$elem" == "$regex" } {
  233. #local output {@slist.Append{{$output};{$elem}}};
  234. };
  235. };
  236. #return {$output};
  237. };
  238. ///=== {
  239. // #@ slist.Contains <字符串列表> <字符串>
  240. // 判断字符串是否在字符串列表中。
  241. // };
  242. #func {slist.Contains} {#return {@math.Eval{@slist.IndexOf{{%1};{%2}} > 0 }}};
  243. ///=== {
  244. // #@ slist.Sort <字符串列表>
  245. // 按照字母顺序重新排序字符串列表中的各项。
  246. //
  247. // #@ slist.Order <字符串列表>
  248. // 按照数值顺序重新排序字符串列表中的各项。
  249. // };
  250. #func {slist.Sort} {#return {@slist.FromList{@list.Sort{@list.FromSlist{%0}}}}};
  251. #func {slist.Order} {#return {@slist.FromList{@list.Order{@list.FromSlist{%0}}}}};
  252. ///=== {
  253. // #@ slist.Reverse <字符串列表>
  254. // 按照倒序重新排列字符串列表内容。
  255. // };
  256. #func {slist.Reverse} {
  257. #return {@slist.FromList{@list.Reverse{@list.FromSlist{%0}}}};
  258. };
  259. ///=== {
  260. // #@ slist.Get <字符串列表> <下标>
  261. // 从字符串列表中按照下标取出一个值。
  262. // };
  263. #func {slist.Get} {
  264. #local list {%1};
  265. #local index {%2};
  266. #local index {@math.Floor{@defaultNum{$index;0}}};
  267. #local n {0};
  268. #local elem {};
  269. #local selected {};
  270. #foreach {$list} {elem} {
  271. #math n {$n + 1};
  272. #if { $index > 0 } {
  273. #if { $n == $index } {
  274. #local selected {$elem};
  275. #if { $index == 1 } {
  276. #line sub {var;escapes} #format selected {%s} {$selected};
  277. };
  278. #break;
  279. };
  280. };
  281. #else {
  282. #math random {1 d $n};
  283. #if { $random == 1 } {
  284. #local selected {$elem};
  285. };
  286. };
  287. };
  288. #return {$selected};
  289. };
  290. ///=== {
  291. // #@ slist.RandomGet <字符串列表>
  292. // 从字符串列表中随机取出一个值。
  293. // };
  294. #func {slist.RandomGet} {
  295. #return {@slist.Get{{%0};}};
  296. };
  297. ///=== {
  298. // #@ slist.Range <开始值> <结束值> [<步长>]
  299. // 生成等差数列,从开始值开始,一直到不超过结束值为止。结果用字符串列表表示。
  300. // 可选的步长用来决定公差,默认为 1。
  301. // 如果开始值小于结束值,则步长自动取正值。
  302. // 如果开始值大于结束值,则步长自动取其负值(如果参数为正则取相反数否则不变)。
  303. // };
  304. #func {slist.Range} {
  305. #local begin {%1};
  306. #local end {%2};
  307. #local delta {@defaultNum{%3;1}};
  308. #local op {<=};
  309. #local delta {@math.Abs{$delta}};
  310. #if { $begin > $end } {
  311. #local op {>=};
  312. #local delta {@math.Eval{- $delta}};
  313. };
  314. #local list {$begin};
  315. #math begin {$begin + $delta};
  316. #while { $begin $op $end } {
  317. #cat list {;$begin};
  318. #math begin {$begin + $delta};
  319. };
  320. #return {$list};
  321. };
  322. ///=== {
  323. // #@ slist.Join <字符串列表> <分隔符> [<是否保留空元素>]
  324. // 将字符串列表的每个元素用分隔符连接在一起。返回连接后的字符串。
  325. // 第三个参数是可选的,用来指定是否保留字符串列表中的空元素。
  326. // 默认不保留,如果想要保留请设置为 true。
  327. // };
  328. #func {slist.Join} {#return {@slist.JoinAs{{%1};;{%2};%3}}};
  329. ///=== {
  330. // #@ slist.JoinAs <字符串列表> <格式串> <分隔符> [<是否保留空元素>]
  331. // 将字符串列表的每个元素用格式串渲染之后,再用分隔符连接在一起。
  332. // 返回连接后的字符串。
  333. // 格式串默认为 %s。
  334. // 第四个参数是可选的,用来指定是否保留字符串列表中的空元素。
  335. // 默认不保留,如果想要保留请设置为 true。
  336. // };
  337. #func {slist.JoinAs} {
  338. #local strList {%1};
  339. #local format {@default{%2;%s}};
  340. #local sep {%3};
  341. #local keepNull {@isTrue{@default{%4;false}}};
  342. #local str {};
  343. #local first {1};
  344. #local elem {};
  345. #foreach {$strList} {elem} {
  346. #if { @isEmpty{$elem} && !$keepNull } {
  347. #continue;
  348. };
  349. #format elem {$format} {$elem};
  350. #if $first {
  351. #local str {$elem};
  352. #local first {0};
  353. };
  354. #else {
  355. #cat str {$sep$elem};
  356. };
  357. };
  358. #return {$str};
  359. };
  360. ///=== {
  361. // #@ slist.Zip <列表1> <列表2> [...]
  362. // 将多个列表合并成一个列表。结果列表的每个元素分别对应参数列表中对应位置的元素。
  363. // 各个参数列表中的元素将按顺序一一对应,以分号分隔连接到一起成为结果列表的元素。
  364. // };
  365. #func {slist.Zip} {
  366. #info arguments save;
  367. #unvar info[ARGUMENTS][0];
  368. #local argv {$info[ARGUMENTS]};
  369. #if { &argv[] < 2 } {
  370. #return {%1};
  371. };
  372. #local i {};
  373. #local maxSize {0};
  374. #loop {1} {&argv[]} {i} {
  375. #local list {};
  376. #list list create {$argv[+$i]};
  377. #local {argv[+$i]} {$list};
  378. #local size {&list[]};
  379. #if { $size > $maxSize } {
  380. #local maxSize $size;
  381. };
  382. };
  383. #if { $maxSize < 1 } {
  384. #return {};
  385. };
  386. #local zipped {};
  387. #loop {1} {$maxSize} {i} {
  388. #local n {};
  389. #local l {};
  390. #loop {1} {&argv[]} {n} {
  391. #if { $i > &argv[+$n][] } {
  392. #list l add {{}};
  393. };
  394. #else {
  395. #list l add {{$argv[+$n][$i]}};
  396. };
  397. };
  398. #list zipped {add} {{@slist.FromList{$l}}};
  399. };
  400. #return {@slist.FromList{$zipped}};
  401. };
  402. ///=== {
  403. // #@ slist.ZipAs <格式串> <列表1> <列表2> [...]
  404. // 将多个列表合并成一个列表。结果列表的每个元素分别对应参数列表中对应位置的元素。
  405. // 合并时使用格式串对所有参数列表中的元素进行格式化合并。
  406. // };
  407. #func {slist.ZipAs} {
  408. #info arguments save;
  409. #unvar info[ARGUMENTS][0];
  410. #local argv {$info[ARGUMENTS]};
  411. #local format {$argv[1]};
  412. #list argv delete {1};
  413. #if { &argv[] < 1 } {
  414. #return {};
  415. };
  416. #local i {};
  417. #local maxSize {0};
  418. #loop {1} {&argv[]} {i} {
  419. #local list {};
  420. #list list create {$argv[+$i]};
  421. #local {argv[+$i]} {$list};
  422. #local size {&list[]};
  423. #if { $size > $maxSize } {
  424. #local maxSize $size;
  425. };
  426. };
  427. #if { $maxSize < 1 } {
  428. #return {};
  429. };
  430. #local zipped {};
  431. #loop {1} {$maxSize} {i} {
  432. #local n {};
  433. #local l {};
  434. #loop {1} {&argv[]} {n} {
  435. #if { $i > &argv[+$n][] } {
  436. #list l add {{}};
  437. };
  438. #else {
  439. #list l add {{$argv[+$n][$i]}};
  440. };
  441. };
  442. #local value {};
  443. #line sub var #format value {$format} $l[];
  444. #list zipped {add} {{$value}};
  445. };
  446. #return {@slist.FromList{$zipped}};
  447. };