From f20ce51928d2369d5f78fe8580d09c4a1c3d3f65 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Mon, 7 Oct 2024 22:26:48 +0800 Subject: [PATCH] feat: pangu Thanks to @NullgramClient Co-authored-by: qwq233 --- .../telegram/messenger/LocaleController.java | 4 +- .../org/telegram/messenger/MessageObject.java | 7 + .../messenger/SendMessagesHelper.java | 47 ++++- .../top/qwq2333/nullgram/utils/StringUtils.kt | 154 ++++++++++++++ .../java/tw/nekomimi/nekogram/NekoConfig.java | 2 + .../tw/nekomimi/nekogram/parts/LocFilters.kt | 14 +- .../NekoExperimentalSettingsActivity.java | 10 + .../src/main/kotlin/ws/vinta/pangu/Pangu.kt | 189 ++++++++++++++++++ .../kotlin/xyz/nextalone/nagram/NaConfig.kt | 12 ++ .../src/main/res/values-zh-rCN/strings_na.xml | 4 + .../src/main/res/values/strings_na.xml | 5 + 11 files changed, 437 insertions(+), 11 deletions(-) create mode 100644 TMessagesProj/src/main/java/top/qwq2333/nullgram/utils/StringUtils.kt create mode 100644 TMessagesProj/src/main/kotlin/ws/vinta/pangu/Pangu.kt diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index d5acc7ec0..830994b69 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -1460,11 +1460,11 @@ public class LocaleController { } } } - if (value == null || "".equals(value)) { + if (value == null || value.isEmpty()) { value = "LOC_ERR:" + key; if (getFallbackResources() != null) value = getFallbackResources().getString(res); - } else { + } else if (NekoConfig.localeToDBC.Bool()) { value = LocFiltersKt.filter(value); } return value; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 6c6131320..829410808 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -42,6 +42,7 @@ import androidx.annotation.NonNull; import androidx.collection.LongSparseArray; import androidx.core.graphics.ColorUtils; +import top.qwq2333.nullgram.utils.StringUtils; import xyz.nextalone.nagram.NaConfig; import xyz.nextalone.nagram.helper.MessageHelper; import xyz.nextalone.nagram.ui.syntaxhighlight.SyntaxHighlight; @@ -1754,6 +1755,12 @@ public class MessageObject { fromUser = getUser(users, sUsers, message.from_id.user_id); } + if (generateLayout && messageOwner.message != null && NaConfig.INSTANCE.getEnablePanguOnReceiving().Bool()) { + var pair = StringUtils.spacingText(messageOwner.message, messageOwner.entities); + messageOwner.message = pair.getFirst(); + messageOwner.entities = pair.getSecond(); + } + updateMessageText(users, chats, sUsers, sChats); setType(); if (generateLayout) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 44a8851eb..dbafd39b0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -102,6 +102,8 @@ import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import kotlin.Pair; +import top.qwq2333.nullgram.utils.StringUtils; import xyz.nextalone.nagram.NaConfig; public class SendMessagesHelper extends BaseController implements NotificationCenter.NotificationCenterDelegate { @@ -1945,7 +1947,16 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (msgObj.getId() <= 0 || msgObj.needDrawBluredPreview()) { if (msgObj.type == MessageObject.TYPE_TEXT && !TextUtils.isEmpty(msgObj.messageText)) { TLRPC.WebPage webPage = msgObj.messageOwner.media != null ? msgObj.messageOwner.media.webpage : null; - SendMessageParams params = SendMessageParams.of(msgObj.messageText.toString(), peer, null, replyToTopMsg, webPage, webPage != null, msgObj.messageOwner.entities, null, null, notify, scheduleDate, null, false); + + var messageText = msgObj.messageText.toString(); + var entities = msgObj.messageOwner.entities; + if (!msgObj.isForwarded() && NaConfig.INSTANCE.getEnablePanguOnSending().Bool()) { + var pair = StringUtils.spacingText(messageText, msgObj.messageOwner.entities); + messageText = pair.getFirst(); + entities = pair.getSecond(); + } + + SendMessageParams params = SendMessageParams.of(messageText, peer, null, replyToTopMsg, webPage, webPage != null, entities, null, null, notify, scheduleDate, null, false); params.quick_reply_shortcut = msgObj.getQuickReplyName(); params.quick_reply_shortcut_id = msgObj.getQuickReplyId(); sendMessage(params); @@ -2107,9 +2118,18 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (newMsg.message == null) { newMsg.message = ""; } + + if (!((newMsg.params.containsKey("fwd_id") || newMsg.params.containsKey("fwd_peer")) || msgObj.isForwarded() || MessageObject.isForwardedMessage(newMsg)) && NaConfig.INSTANCE.getEnablePanguOnSending().Bool()) { + var pair = StringUtils.spacingText(newMsg.message, msgObj.messageOwner.entities); + newMsg.message = pair.getFirst(); + newMsg.entities = pair.getSecond(); + } else { + newMsg.entities = msgObj.messageOwner.entities; + } + newMsg.fwd_msg_id = msgObj.getId(); newMsg.attachPath = msgObj.messageOwner.attachPath; - newMsg.entities = msgObj.messageOwner.entities; +// newMsg.entities = msgObj.messageOwner.entities; if (msgObj.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) { newMsg.reply_markup = new TLRPC.TL_replyInlineMarkup(); boolean dropMarkup = false; @@ -3760,6 +3780,14 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } else { newMsg = new TLRPC.TL_message(); } + + if (poll.poll != null && NaConfig.INSTANCE.getEnablePanguOnSending().Bool()) { + poll.poll.question = StringUtils.spacingText(poll.poll.question); + for (int i = 0; i < poll.poll.answers.size(); i++) { + poll.poll.answers.get(i).text = StringUtils.spacingText(poll.poll.answers.get(i).text); + } + } + newMsg.media = poll; type = 10; } else if (location != null) { @@ -4227,6 +4255,21 @@ public class SendMessagesHelper extends BaseController implements NotificationCe isFinalGroupMedia = params.get("final") != null; } + if (!((params != null && params.containsKey("fwd_id")) || MessageObject.isForwardedMessage(newMsg)) && NaConfig.INSTANCE.getEnablePanguOnSending().Bool()) { + Pair> pair; + if (caption != null) { + pair = StringUtils.spacingText(caption, entities); + caption = pair.getFirst(); + } else { + pair = StringUtils.spacingText(message, entities); + message = pair.getFirst(); + } + entities = pair.getSecond(); + + newMsg.message = pair.getFirst(); + newMsg.entities = pair.getSecond(); + } + if (stars > 0) { TLRPC.MessageMedia media = newMsg.media; TLRPC.TL_messageMediaPaidMedia paidMedia = new TLRPC.TL_messageMediaPaidMedia(); diff --git a/TMessagesProj/src/main/java/top/qwq2333/nullgram/utils/StringUtils.kt b/TMessagesProj/src/main/java/top/qwq2333/nullgram/utils/StringUtils.kt new file mode 100644 index 000000000..c8386be92 --- /dev/null +++ b/TMessagesProj/src/main/java/top/qwq2333/nullgram/utils/StringUtils.kt @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2019-2024 qwq233 + * https://github.com/qwq233/Nullgram + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this software. + * If not, see + * + */ +package top.qwq2333.nullgram.utils + +import org.telegram.tgnet.TLRPC +import ws.vinta.pangu.Pangu +import kotlin.math.ceil + +object StringUtils { + private val pangu = Pangu() + + /** + * + * 字符串是否为空白,空白的定义如下: + * + * 1. `null` + * 1. 空字符串:`""` + * 1. 空格、全角空格、制表符、换行符,等不可见字符 + * + * + * + * 例: + * + * * `StringUtils.isBlank(null) // true` + * * `StringUtils.isBlank("") // true` + * * `StringUtils.isBlank(" \t\n") // true` + * * `StringUtils.isBlank("abc") // false` + * + * + * @param str 被检测的字符串 + * @return 若为空白,则返回 true + */ + @JvmStatic + fun isBlank(str: CharSequence?): Boolean { + if (str.isNullOrEmpty()) { + return true + } + val length: Int = str.length + for (i in 0 until length) { + // 只要有一个非空字符即为非空字符串 + if (!isBlankChar(str[i])) { + return false + } + } + return true + } + + /** + * 是否空白符

+ * 空白符包括空格、制表符、全角空格和不间断空格

+ * + * @param c 字符 + * @return 是否空白符 + * @see Character.isWhitespace + * @see Character.isSpaceChar + */ + fun isBlankChar(c: Int): Boolean { + return Character.isWhitespace(c) || Character.isSpaceChar(c) || c == '\ufeff'.code || c == '\u202a'.code || c == '\u0000'.code + } + + /** + * 是否空白符

+ * 空白符包括空格、制表符、全角空格和不间断空格

+ * + * @param c 字符 + * @return 是否空白符 + * @see Character.isWhitespace + * @see Character.isSpaceChar + */ + fun isBlankChar(c: Char): Boolean { + return isBlankChar(c.code) + } + + /** + * Return a string with a maximum length of `length` characters. + * If there are more than `length` characters, then string ends with an ellipsis ("..."). + * + * @param text text + * @param length maximum length you want + * @return Return a string with a maximum length of `length` characters. + */ + @JvmStatic + @Suppress("NAME_SHADOWING") + fun ellipsis(text: String, length: Int): String { + // The letters [iIl1] are slim enough to only count as half a character. + var length = length + length += ceil(text.replace("[^iIl]".toRegex(), "").length / 2.0).toInt() + return if (text.length > length) { + text.substring(0, length - 3) + "..." + } else text + } + + @JvmStatic + fun spacingText(message: TLRPC.TL_textWithEntities): TLRPC.TL_textWithEntities { + return TLRPC.TL_textWithEntities().apply { + val pair = spacingText(message.text, message.entities) + text = pair.first + entities = pair.second + } + } + + @JvmStatic + fun spacingText(text: String, entities: ArrayList?): Pair?> { + if (text.startsWith("/")) return Pair(text, entities) // command + if (entities.isNullOrEmpty()) return Pair(pangu.spacingText(text), entities) + + val panguText = pangu.spacingText(text) + + if (panguText.length == text.length) return Pair(panguText, entities) // processed or unnecessary + + var skip = 0 + for (i in text.indices) { + if (i + skip >= panguText.length) break + if (text[i] == panguText[i + skip]) continue + + entities.forEach { + if (it.offset >= i + skip) { // text is after this entity + it.offset += 1 + } else if (it.offset + it.length >= i + skip) { // text is in this entity + it.length += 1 + } // text is before this entity + } + skip += 1 + } + + // prevent out of bound + entities.forEach { + if (it.offset >= panguText.length) { + it.offset = panguText.length - 1 + } + if (it.offset + it.length > panguText.length) { + it.length = panguText.length - it.offset + } + } + + return Pair(panguText, entities) + } +} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java index 36a643550..acc6d4d4a 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/NekoConfig.java @@ -196,6 +196,8 @@ public class NekoConfig { // priv branch changes public static ConfigItem localPremium = addConfig("localPremium", configTypeBool, false); + public static ConfigItem localeToDBC = addConfig("LocaleToDBC", configTypeBool, false); + static { loadConfig(false); checkMigrate(false); diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/LocFilters.kt b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/LocFilters.kt index d63f4a37c..6238b830a 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/LocFilters.kt +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/parts/LocFilters.kt @@ -1,12 +1,12 @@ package tw.nekomimi.nekogram.parts private val mapArr = mapOf( - '(' to '(', - ')' to ')', - '。' to '.', - ',' to ',', - '?' to '?', - ';' to ';' + '(' to '(', + ')' to ')', + '。' to '.', + ',' to ',', + '?' to '?', + ';' to ';' ) fun filter(input: String) = input.toCharArray().let { c -> @@ -21,4 +21,4 @@ fun filter(input: String) = input.toCharArray().let { c -> listOf(char) } }.filterNotNull().toCharArray().let(::String) -} \ No newline at end of file +} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java index 831108900..8df6ecc79 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/settings/NekoExperimentalSettingsActivity.java @@ -127,6 +127,7 @@ public class NekoExperimentalSettingsActivity extends BaseNekoXSettingsActivity private final AbstractConfigCell disableSendReadStoriesRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getDisableSendReadStories())); private final AbstractConfigCell dividerStory = cellGroup.appendCell(new ConfigCellDivider()); + // Sticker Cache private final AbstractConfigCell header3 = cellGroup.appendCell(new ConfigCellHeader(LocaleController.getString(R.string.ExternalStickerCache))); private final AbstractConfigCell externalStickerCacheRow = cellGroup.appendCell(new ConfigCellAutoTextCheck( NaConfig.INSTANCE.getExternalStickerCache(), LocaleController.getString(R.string.ExternalStickerCacheHint), this::onExternalStickerCacheButtonClick)); @@ -136,6 +137,13 @@ public class NekoExperimentalSettingsActivity extends BaseNekoXSettingsActivity private final AbstractConfigCell externalStickerCacheDeleteAllRow = cellGroup.appendCell(new ConfigCellText("ExternalStickerCacheDeleteAll", ExternalStickerCacheHelper::deleteAllCaches)); private final AbstractConfigCell divider2 = cellGroup.appendCell(new ConfigCellDivider()); + // Pangu + private final AbstractConfigCell header4 = cellGroup.appendCell(new ConfigCellHeader(LocaleController.getString(R.string.Pangu))); + private final AbstractConfigCell enablePanguOnSendingRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getEnablePanguOnSending(), LocaleController.getString(R.string.PanguInfo))); + private final AbstractConfigCell enablePanguOnReceivingRow = cellGroup.appendCell(new ConfigCellTextCheck(NaConfig.INSTANCE.getEnablePanguOnReceiving())); + private final AbstractConfigCell localeToDBCRow = cellGroup.appendCell(new ConfigCellTextCheck(NekoConfig.localeToDBC)); + private final AbstractConfigCell divider3 = cellGroup.appendCell(new ConfigCellDivider()); + private UndoView tooltip; private static final int INTENT_PICK_CUSTOM_EMOJI_PACK = 114; @@ -359,6 +367,8 @@ public class NekoExperimentalSettingsActivity extends BaseNekoXSettingsActivity intent.setType("application/zip"); Activity act = getParentActivity(); act.startActivityFromChild(act, intent, INTENT_PICK_CUSTOM_EMOJI_PACK); + } else if (key.equals(NekoConfig.localeToDBC.getKey())) { + tooltip.showWithAction(0, UndoView.ACTION_NEED_RESATRT, null, null); } }; diff --git a/TMessagesProj/src/main/kotlin/ws/vinta/pangu/Pangu.kt b/TMessagesProj/src/main/kotlin/ws/vinta/pangu/Pangu.kt new file mode 100644 index 000000000..4ce0e215c --- /dev/null +++ b/TMessagesProj/src/main/kotlin/ws/vinta/pangu/Pangu.kt @@ -0,0 +1,189 @@ +/* + * Created by Vinta Chen on 2014/11/05. + * Modified by qwq233 on 2023/07/17 + */ +package ws.vinta.pangu + +import java.io.IOException +import java.util.regex.Pattern + +/** + * Paranoid text spacing for good readability, to automatically insert whitespace between + * CJK (Chinese, Japanese, Korean), half-width English, digit and symbol characters. + * + * + * These whitespaces between English and Chinese characters are called "Pangu Spacing" by sinologist, since it + * separate the confusion between full-width and half-width characters. Studies showed that who dislike to + * add whitespace between English and Chinese characters also have relationship problem. Almost 70 percent of them + * will get married to the one they don't love, the rest only can left the heritage to their cat. Indeed, + * love and writing need some space in good time. + * + * @author Vinta Chen + * @author qwq233 + * @since 1.0.0 + */ +class Pangu { + companion object { + /* + * Some capturing group patterns for convenience. + * + * CJK: Chinese, Japanese, Korean + * ANS: Alphabet, Number, Symbol + */ + private val CJK_ANS = Pattern.compile( + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + + "([a-z0-9`~@\\$%\\^&\\*\\-_\\+=\\|\\\\/])", + Pattern.CASE_INSENSITIVE + ) + private val ANS_CJK = Pattern.compile( + "([a-z0-9`~!\\$%\\^&\\*\\-_\\+=\\|\\\\;:,\\./\\?])" + + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])", + Pattern.CASE_INSENSITIVE + ) + private val CJK_QUOTE = Pattern.compile( + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + + "([\"'])" + ) + private val QUOTE_CJK = Pattern.compile( + "([\"'])" + + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + ) + private val FIX_QUOTE = Pattern.compile("([\"'])(\\s*)(.+?)(\\s*)([\"'])") + private val CJK_BRACKET_CJK = Pattern.compile( + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + + "([\\({\\[]+(.*?)[\\)}\\]]+)" + + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + ) + private val CJK_BRACKET = Pattern.compile( + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + + "([\\(\\){}\\[\\]<>])" + ) + private val BRACKET_CJK = Pattern.compile( + "([\\(\\){}\\[\\]<>])" + + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + ) + private val FIX_BRACKET = Pattern.compile("([(\\({\\[)]+)(\\s*)(.+?)(\\s*)([\\)}\\]]+)") + private val CJK_HASH = Pattern.compile( + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + + "(#(\\S+))" + ) + private val HASH_CJK = Pattern.compile( + "((\\S+)#)" + + "([\\p{InHiragana}\\p{InKatakana}\\p{InBopomofo}\\p{InCJKCompatibilityIdeographs}\\p{InCJKUnifiedIdeographs}])" + ) + } + + private fun processUrl(text: String) = Pattern.compile("://").matcher(text).let { matcher -> + if (!matcher.find()) { + throw NullPointerException("No URL found in text") + } + var prefixOffset = 0 + val prefix: String = StringBuilder().apply { + arrayListOf().apply { + for (i in matcher.start() - 1 downTo 0) { + val c = text[i] + if (c.isWhitespace()) { + prefixOffset = i + 1 + break + } + add(c) + } + }.reversed().forEach { append(it) } + }.toString() + + var suffixOffset = text.lastIndex + val suffix: String = StringBuilder().apply { + arrayListOf().apply { + for (i in matcher.end() until text.length) { + val c = text[i] + if (c.isWhitespace()) { + suffixOffset = i + break + } + add(c) + } + }.forEach { append(it) } + }.toString() + + val url = "$prefix://$suffix" + val first: String? = if (0 != prefixOffset) text.substring(0, prefixOffset) else null + val last: String? = if (text.lastIndex != suffixOffset) text.substring(suffixOffset) else null + + Triple(first, url, last) + } + + + /** + * Performs a paranoid text spacing on `text`. + * + * @param text the string you want to process, must not be `null`. + * @return a comfortable and readable version of `text` for paranoiac. + */ + fun spacingText(text: String): String { + var text: String = text + + // URL + if (text.contains("://")) { + val (first, url, last) = processUrl(text) + var result = String() + if (first != null) { + result += spacingText(first) + } + result += url + if (last != null) { + result += spacingText(last) + } + return result + } + + // CJK and quotes + val cqMatcher = CJK_QUOTE.matcher(text) + text = cqMatcher.replaceAll("$1 $2") + val qcMatcher = QUOTE_CJK.matcher(text) + text = qcMatcher.replaceAll("$1 $2") + val fixQuoteMatcher = FIX_QUOTE.matcher(text) + text = fixQuoteMatcher.replaceAll("$1$3$5") + + // CJK and brackets + val oldText = text + val cbcMatcher = CJK_BRACKET_CJK.matcher(text) + val newText = cbcMatcher.replaceAll("$1 $2 $4") + text = newText + if (oldText == newText) { + val cbMatcher = CJK_BRACKET.matcher(text) + text = cbMatcher.replaceAll("$1 $2") + val bcMatcher = BRACKET_CJK.matcher(text) + text = bcMatcher.replaceAll("$1 $2") + } + val fixBracketMatcher = FIX_BRACKET.matcher(text) + text = fixBracketMatcher.replaceAll("$1$3$5") + + // CJK and hash + val chMatcher = CJK_HASH.matcher(text) + text = chMatcher.replaceAll("$1 $2") + val hcMatcher = HASH_CJK.matcher(text) + text = hcMatcher.replaceAll("$1 $3") + + // CJK and ANS + val caMatcher = CJK_ANS.matcher(text) + text = caMatcher.replaceAll("$1 $2") + val acMatcher = ANS_CJK.matcher(text) + text = acMatcher.replaceAll("$1 $2") + + return text + } + + private fun log(text: String) { + println("panguTrace: $text") + } + +} + +internal object Test { + @Throws(IOException::class) + @JvmStatic + fun main(args: Array) { + val pangu = Pangu() + println(pangu.spacingText("當你凝視著 https://telegra.ph/八尋ぽち-ひみチュッ-中国翻訳-無修正-DL版-06-17-3 ,bug也凝視著 https://telegra.ph/ASDF-DL版-06-17-3")) + } +} diff --git a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt index 05f3f3167..c1587dbd0 100644 --- a/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt +++ b/TMessagesProj/src/main/kotlin/xyz/nextalone/nagram/NaConfig.kt @@ -640,6 +640,18 @@ object NaConfig { ConfigItem.configTypeString, "" ) + val enablePanguOnSending = + addConfig( + "EnablePanguOnSending", + ConfigItem.configTypeBool, + false + ) + val enablePanguOnReceiving = + addConfig( + "EnablePanguOnReceiving", + ConfigItem.configTypeBool, + false + ) private fun addConfig( k: String, diff --git a/TMessagesProj/src/main/res/values-zh-rCN/strings_na.xml b/TMessagesProj/src/main/res/values-zh-rCN/strings_na.xml index 7a8dfbcc1..4c352dab4 100644 --- a/TMessagesProj/src/main/res/values-zh-rCN/strings_na.xml +++ b/TMessagesProj/src/main/res/values-zh-rCN/strings_na.xml @@ -159,4 +159,8 @@ 在频道点击标签默认搜索页面 在其他对话点击标签默认搜索页面 指定 URL Regex 跳出 bot webview + 界面文本使用半角符号 + 接受信息 Pangu 化 + 发送信息 Pangu 化 + 使文字更具可读性。在 CJK(中文、日文、韩文)、半宽英文、数字和符号字符之间间隔中自动插入空格 diff --git a/TMessagesProj/src/main/res/values/strings_na.xml b/TMessagesProj/src/main/res/values/strings_na.xml index ff20d0c52..cd4270cbb 100644 --- a/TMessagesProj/src/main/res/values/strings_na.xml +++ b/TMessagesProj/src/main/res/values/strings_na.xml @@ -159,4 +159,9 @@ Channel Click Hashtag Default Search Page Chat Click Hashtag Default Search Page Url regex to jump out of bot webview + Locale text using DBC case + Pangu + Enable Pangu on receiving + Enable Pangu on sending + Paranoid text spacing for good readability, to automatically insert whitespace between CJK (Chinese, Japanese, Korean), half-width English, digit and symbol characters.