Skip to content

Commit c437d68

Browse files
authored
♻️ 新手嘗試重構 (#7)
* Modify some functions make it to be more semantic * Extract crawler logic and filter logic to new class file * Extract writing enum file logic and cleanup the code * Replace with buildList functions and make it more compact * Replace explic return with implicit return, make it more "Kotlin" * Relpace explicit return with implicit return, make it more "Kotlin" * Introduce multiline string template and do some code styling
1 parent b898377 commit c437d68

File tree

4 files changed

+156
-107
lines changed

4 files changed

+156
-107
lines changed
Lines changed: 6 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,11 @@
11
package net.purefunc.generate
22

3-
import java.io.BufferedReader
4-
import java.io.File
5-
import java.io.FileOutputStream
6-
import java.io.InputStreamReader
7-
import java.net.URL
8-
import java.util.Locale
3+
import net.purefunc.generate.util.EmojiFileCreator
4+
import net.purefunc.generate.util.EmojiReader
5+
import net.purefunc.generate.util.ValidEmojiCollector
96

107
fun main() {
11-
// collect emoji lines
12-
// 1F636 200D 1F32B FE0F ; fully-qualified # 😶‍🌫️ E13.1 face in clouds
13-
var flag = false
14-
val lines = mutableListOf<String>()
15-
val url = URL("https://unicode.org/Public/emoji/15.0/emoji-test.txt")
16-
val reader = BufferedReader(InputStreamReader(url.openConnection().getInputStream()))
17-
reader.useLines { readLines ->
18-
readLines.forEach { line ->
19-
if (line == "") flag = false
20-
if (flag) lines.add(line)
21-
if (line.startsWith("# subgroup: ")) flag = true
22-
}
23-
}
24-
25-
val bigEnum = lines.filter {
26-
it.contains("fully-qualified")
27-
}.map {
28-
it.split(" ")
29-
}.map { elements ->
30-
// [1F636, 200D, 1F32B, FE0F, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ;, fully-qualified, , , , , #, 😶‍🌫️, E13.1, face, in, cloud]
31-
32-
val items = mutableListOf<String>()
33-
34-
val codePartIdxs = elements.mapIndexed { idx, element -> if (element == "" || element == ";") idx else -1 }
35-
val codeIdx = codePartIdxs.filter { idx -> idx != -1 }[0]
36-
37-
(0 until codeIdx).forEach { i -> items.add(elements[i]) }
38-
items.add(";")
39-
40-
val namePartIdxs =
41-
elements.mapIndexed { idx, element -> if (element.startsWith("E") && element.contains(".")) idx else -1 }
42-
val nameIdx = namePartIdxs.filter { idx -> idx != -1 }[0]
43-
44-
items.addAll(
45-
// replace item name contains invalid char
46-
elements.subList(nameIdx + 1, elements.size).map { str ->
47-
str.replace("", "")
48-
.replace("", "")
49-
.replace("", "")
50-
.replace("-", "_")
51-
.replace(":", "")
52-
.replace(".", "")
53-
.replace("!", "")
54-
.replace("(", "")
55-
.replace(")", "")
56-
.replace("1st", "first")
57-
.replace("2nd", "second")
58-
.replace("3rd", "third")
59-
.replace("package", "packages")
60-
.replace("#", "hash")
61-
.replace("*", "star")
62-
.replace(",", "comma")
63-
.replace("&", "and")
64-
}
65-
)
66-
67-
items
68-
}
69-
70-
// all enum in one .kt is will exceed jvm limit 64K
71-
val pageCount = 1000
72-
val pageSize = (bigEnum.size / pageCount)
73-
val pagingItems = (0..pageSize).map { page ->
74-
if (pageCount * (page + 1) > bigEnum.size) {
75-
bigEnum.subList(pageCount * page, bigEnum.size)
76-
} else {
77-
bigEnum.subList(pageCount * page, pageCount * (page + 1))
78-
}
79-
}
80-
81-
pagingItems.forEachIndexed { fileIdx, item ->
82-
val fos = FileOutputStream(File("src/main/kotlin/net/purefunc/emoji/Emoji$fileIdx.kt"))
83-
fos.write("package net.purefunc.emoji\n".toByteArray())
84-
fos.write("\n".toByteArray())
85-
fos.write("enum class Emoji$fileIdx(\n".toByteArray())
86-
fos.write(" private val intArray: IntArray,\n".toByteArray())
87-
fos.write(") {\n".toByteArray())
88-
fos.write("\n".toByteArray())
89-
90-
item.forEachIndexed { idx, element ->
91-
val idxListThird = element.mapIndexed { i, e -> if (e == ";") i else -1 }
92-
val splitIdx = idxListThird.filter { i -> i != -1 }[0]
93-
94-
val name = element.subList(splitIdx + 1, element.size).joinToString("_").uppercase(Locale.getDefault())
95-
val hexs = element.subList(0, splitIdx).map { hex -> "0x$hex" }.joinToString(",")
96-
val emojiIntArr = element.subList(0, splitIdx).map { hex -> hex.toInt(16) }.toIntArray()
97-
val emoji = String(emojiIntArr, 0, emojiIntArr.size)
98-
99-
val comment = " // $emoji $emoji $emoji"
100-
val enum = " $name(intArrayOf($hexs))"
101-
if (idx == item.size - 1) {
102-
fos.write("$comment\n$enum;\n".toByteArray())
103-
} else {
104-
fos.write("$comment\n$enum,\n".toByteArray())
105-
}
106-
}
107-
108-
fos.write("\n".toByteArray())
109-
fos.write(" override fun toString() = String(intArray, 0, intArray.size)\n".toByteArray())
110-
fos.write("}\n".toByteArray())
111-
}
8+
val roughList = EmojiReader("https://unicode.org/Public/emoji/15.0/emoji-test.txt").readTargetUrl()
9+
val bigEnum = ValidEmojiCollector(roughList).filter()
10+
EmojiFileCreator(1000).writeAsEnumFile(bigEnum)
11211
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package net.purefunc.generate.util
2+
3+
import java.io.File
4+
import java.io.FileOutputStream
5+
import java.util.*
6+
7+
class EmojiFileCreator(private val pageCount: Int) {
8+
// all enum in one .kt is will exceed jvm limit 64K
9+
fun writeAsEnumFile(source: List<List<String>>): Unit {
10+
val pagingItems = allocatePerPageItem(source)
11+
12+
pagingItems.forEachIndexed { fileIdx, item ->
13+
val fos = FileOutputStream(File("src/main/kotlin/net/purefunc/emoji/Emoji$fileIdx.kt"))
14+
fos.generateFileHeader(fileIdx)
15+
16+
item.forEachIndexed { idx, element ->
17+
val idxListThird = element.mapIndexed { i, e -> if (e == ";") i else -1 }
18+
val splitIdx = idxListThird.first { i -> i != -1 }
19+
20+
val name = element.subList(splitIdx + 1, element.size).joinToString("_").uppercase(Locale.getDefault())
21+
val hexs = element.subList(0, splitIdx).joinToString(",") { hex -> "0x$hex" }
22+
val emojiIntArr = element.subList(0, splitIdx).map { hex -> hex.toInt(16) }.toIntArray()
23+
val emoji = String(emojiIntArr, 0, emojiIntArr.size)
24+
25+
val comment = " // $emoji $emoji $emoji"
26+
val enum = " $name(intArrayOf($hexs))"
27+
if (idx == item.size - 1) {
28+
fos.writeLastLine(comment, enum)
29+
} else {
30+
fos.writeNextLine(comment, enum)
31+
}
32+
}
33+
34+
fos.generateFileFooter()
35+
}
36+
}
37+
38+
private fun allocatePerPageItem(source: List<List<String>>): List<List<List<String>>> {
39+
val pageSize = (source.size / pageCount)
40+
return (0..pageSize).map { page ->
41+
val pageList: (Int) -> List<List<String>> = { source.subList(pageCount * page, it) }
42+
if (pageCount * (page + 1) > source.size)
43+
pageList(source.size)
44+
else
45+
pageList(pageCount * (page + 1))
46+
47+
}
48+
}
49+
50+
private fun FileOutputStream.generateFileHeader(fileIdx: Int) =
51+
write(
52+
"""
53+
package net.purefunc.emoji
54+
55+
enum class Emoji$fileIdx(
56+
private val intArray: IntArray,
57+
) {
58+
59+
60+
""".trimIndent().toByteArray()
61+
)
62+
63+
private fun FileOutputStream.writeNextLine(comment: String, enum: String) = write("$comment\n$enum,\n".toByteArray())
64+
65+
private fun FileOutputStream.writeLastLine(comment: String, enum: String) = write("$comment\n$enum;\n".toByteArray())
66+
67+
private fun FileOutputStream.generateFileFooter() =
68+
write(
69+
"""
70+
71+
override fun toString() = String(intArray, 0, intArray.size)
72+
}
73+
74+
""".trimIndent().toByteArray()
75+
)
76+
77+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package net.purefunc.generate.util
2+
3+
import java.io.BufferedReader
4+
import java.io.InputStreamReader
5+
import java.net.URL
6+
7+
class EmojiReader(private val targetUrl: String) {
8+
9+
fun readTargetUrl(): List<String> =
10+
// collect emoji lines
11+
// 1F636 200D 1F32B FE0F ; fully-qualified # 😶‍🌫️ E13.1 face in clouds
12+
buildList {
13+
var flag = false
14+
val reader = BufferedReader(InputStreamReader(URL(targetUrl).openConnection().getInputStream()))
15+
reader.useLines { readLines ->
16+
readLines.forEach { line ->
17+
if (line.isEmpty()) flag = false
18+
if (flag) add(line)
19+
if (line.startsWith("# subgroup: ")) flag = true
20+
}
21+
}
22+
}
23+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package net.purefunc.generate.util
2+
3+
class ValidEmojiCollector(private val source: List<String>) {
4+
5+
fun filter() =
6+
source
7+
.filter {
8+
it.contains("fully-qualified")
9+
}.map {
10+
it.split(" ")
11+
}.map { elements ->
12+
// [1F636, 200D, 1F32B, FE0F, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ;, fully-qualified, , , , , #, 😶‍🌫️, E13.1, face, in, cloud]
13+
14+
val items = mutableListOf<String>()
15+
16+
val codePartIdxs = elements.mapIndexed { idx, element -> if (element.isEmpty() || element == ";") idx else -1 }
17+
val codeIdx = codePartIdxs.first { idx -> idx != -1 }
18+
19+
(0 until codeIdx).forEach { i -> items.add(elements[i]) }
20+
items.add(";")
21+
22+
val namePartIdxs =
23+
elements.mapIndexed { idx, element -> if (element.startsWith("E") && element.contains(".")) idx else -1 }
24+
val nameIdx = namePartIdxs.first { idx -> idx != -1 }
25+
26+
items.plus(elements.subList(nameIdx + 1, elements.size).map { str -> convertToValidChar(str) })
27+
}
28+
29+
30+
private fun convertToValidChar(str: String) =
31+
// replace item name contains invalid char
32+
str.replace("", "")
33+
.replace("", "")
34+
.replace("", "")
35+
.replace("-", "_")
36+
.replace(":", "")
37+
.replace(".", "")
38+
.replace("!", "")
39+
.replace("(", "")
40+
.replace(")", "")
41+
.replace("1st", "first")
42+
.replace("2nd", "second")
43+
.replace("3rd", "third")
44+
.replace("package", "packages")
45+
.replace("#", "hash")
46+
.replace("*", "star")
47+
.replace(",", "comma")
48+
.replace("&", "and")
49+
50+
}

0 commit comments

Comments
 (0)