fix(crn): 修复CRN聚合站(如「千叶」)在CC中文环境下变????导致校正匹配失败引发终点站广播漏播

- 新增 extractAlphaNumCodes / hasSharedAlphaNumCode: 提取并比对字母数字代码(CB-03,CE-09等), 在中文变问号乱码环境下仍可通过代码完成跨源匹配
- looksLikeValidDestinationText: 放宽校验, 若问号超过50%但仍存在有效字母数字代码(如「????CB-03 6」)时不直接判为无效——保留代码供后续 hasSharedAlphaNumCode 匹配
- tryCorrectUpcomingEntryWithCurrentTrain:
  1) 新增 etaSeconds 形参用于识别在站列车(eta≤0.5s), 据此触发校正
  2) 新增 nearbyPlatform 条件: 站台号数字差≤1 时也进入校正候选
  3) 新增 sharedCodeDest / sharedCodeTrain: 即使车次/站台全不匹配, 只要 dest 或 id 含有与权威值相同的字母数字代码即可触发
  4) 新增兜底触发: (dest或id无效且eta=0)  |  (双无效且相邻站台)  —— 专门覆盖CRN聚合名????这种彻底无代码的场景
  5) 新增校正分支: 只要 sharedCodeTrain/sharedCodeDest 命中且 (etaAtStation|samePlatform|invalid) 即直接覆盖原值, 无需 fuzzy match 再次通过
- checkIsAtStationWithCurrentTrain:
  1) 无 sameTrain 时用 hasSharedAlphaNumCode 二次匹配车次
  2) 若车次/目的地双乱码 + 站台相邻, 也视为同车
  3) 乱码目的地分支新增 hasSharedAlphaNumCode 成功即判停靠成功
- BlockReader/CreateTarget 两处预校正均移至 etaSeconds 计算之后, 并将 eta 传入函数, 确保看门条件里的 etaAtStation 可生效
- 全局校正循环也传入 entry.eta

版本升级至 v1.0.72
This commit is contained in:
2026-08-16 13:25:39 +08:00
parent 716a23cad5
commit cd5b1d47b0
+123 -39
View File
@@ -1,6 +1,6 @@
-- 1. Configuration & Constants
local APP_VERSION_TEXT = "v1.0.71"
local APP_VERSION_TEXT = "v1.0.72"
local CONFIG = {
CLOUD_URL = "ws://stabadmin.fse-media.group",
@@ -3042,6 +3042,45 @@ local function isStationDestination(destName)
return true
end
local function extractAlphaNumCodes(text)
if not text then return {} end
local s = tostring(text)
local codes = {}
for code in string.gmatch(s, "[%a%d]+%-[%a%d]+") do
codes[code] = true
end
for code in string.gmatch(s, "%a+%d+") do
codes[code] = true
end
for code in string.gmatch(s, "%d+") do
codes[code] = true
end
local list = {}
for k, _ in pairs(codes) do
table.insert(list, k)
end
return list
end
local function hasSharedAlphaNumCode(a, b)
local codes1 = extractAlphaNumCodes(a)
local codes2 = extractAlphaNumCodes(b)
if #codes1 == 0 or #codes2 == 0 then return false end
for _, c1 in ipairs(codes1) do
for _, c2 in ipairs(codes2) do
if c1 == c2 then return true end
local lc1, lc2 = string.lower(c1), string.lower(c2)
if lc1 == lc2 then return true end
if #lc1 >= 3 and #lc2 >= 3 then
if string.find(lc1, lc2, 1, true) or string.find(lc2, lc1, 1, true) then
return true
end
end
end
end
return false
end
local function looksLikeValidDestinationText(text)
if not text then return false end
local s = tostring(text)
@@ -3053,7 +3092,10 @@ local function looksLikeValidDestinationText(text)
local c = string.sub(s, i, i)
if c == "?" then questionMarkCount = questionMarkCount + 1 end
end
if #s > 0 and questionMarkCount / #s >= 0.5 then return false end
if #s > 0 and questionMarkCount / #s >= 0.5 then
local codes = extractAlphaNumCodes(s)
if #codes == 0 then return false end
end
local hasRealChar = false
for i = 1, #s do
local b = string.byte(s, i)
@@ -3066,7 +3108,7 @@ local function looksLikeValidDestinationText(text)
return isStationDestination(s)
end
local function tryCorrectUpcomingEntryWithCurrentTrain(entry)
local function tryCorrectUpcomingEntryWithCurrentTrain(entry, etaSeconds)
if not State.currentTrain or not entry then return entry end
local ctId = State.currentTrain.id
local ctDest = State.currentTrain.dest
@@ -3077,7 +3119,29 @@ local function tryCorrectUpcomingEntryWithCurrentTrain(entry)
if ctId and entry.trainName then
sameTrain = Utils.isSameTrain(ctId, entry.trainName)
end
if not sameTrain and not samePlatform then return entry end
local platformNum = tonumber((string.gsub(entryPlatform, "%D", "")))
local ctPlatformNum = tonumber((string.gsub(ctPlatform, "%D", "")))
local nearbyPlatform = false
if platformNum and ctPlatformNum then
nearbyPlatform = (math.abs(platformNum - ctPlatformNum) <= 1)
end
local sharedCodeDest = hasSharedAlphaNumCode(entry.dest, ctDest)
local sharedCodeTrain = hasSharedAlphaNumCode(entry.trainName, ctId)
local etaAtStation = (type(etaSeconds) == "number" and etaSeconds <= 0.5)
local destInvalid = not looksLikeValidDestinationText(entry.dest)
local idInvalid = not looksLikeValidDestinationText(entry.trainName)
local shouldCorrect = samePlatform or sameTrain
or (sharedCodeDest and (nearbyPlatform or etaAtStation))
or (sharedCodeTrain and (nearbyPlatform or etaAtStation))
or ((destInvalid or idInvalid) and etaAtStation)
or (destInvalid and idInvalid and nearbyPlatform)
if not shouldCorrect then return entry end
local validId = looksLikeValidDestinationText(entry.trainName)
local validDest = looksLikeValidDestinationText(entry.dest)
@@ -3085,19 +3149,25 @@ local function tryCorrectUpcomingEntryWithCurrentTrain(entry)
entry.trainName = ctId
end
if sameTrain and ctId and ctId ~= "" and tostring(entry.trainName or "") ~= tostring(ctId) then
if Utils.isFuzzyMatch(entry.trainName or "", ctId) or not validId then
if Utils.isFuzzyMatch(entry.trainName or "", ctId) or not validId or sharedCodeTrain then
entry.trainName = ctId
end
end
if ctId and ctId ~= "" and tostring(entry.trainName or "") ~= tostring(ctId) and sharedCodeTrain and (etaAtStation or samePlatform or idInvalid) then
entry.trainName = ctId
end
if not validDest and ctDest and ctDest ~= "" then
entry.dest = ctDest
end
if (sameTrain or samePlatform) and ctDest and ctDest ~= "" and tostring(entry.dest or "") ~= tostring(ctDest) then
if Utils.isFuzzyMatch(entry.dest or "", ctDest) or not validDest then
if (sameTrain or samePlatform or sharedCodeDest) and ctDest and ctDest ~= "" and tostring(entry.dest or "") ~= tostring(ctDest) then
if Utils.isFuzzyMatch(entry.dest or "", ctDest) or not validDest or sharedCodeDest or etaAtStation then
entry.dest = ctDest
end
end
if ctDest and ctDest ~= "" and tostring(entry.dest or "") ~= tostring(ctDest) and sharedCodeDest and (etaAtStation or samePlatform or destInvalid) then
entry.dest = ctDest
end
return entry
end
@@ -3125,6 +3195,16 @@ local function checkIsAtStationWithCurrentTrain(trainName, destination, platform
end
end
end
if not sameTrain and hasSharedAlphaNumCode(trainName, ctId) then
sameTrain = true
end
if not sameTrain and (not looksLikeValidDestinationText(trainName)) and (not looksLikeValidDestinationText(destination)) then
local pNum = tonumber((string.gsub(trainPlatform, "%D", "")))
local ctPNum = tonumber((string.gsub(ctPlatform, "%D", "")))
if pNum and ctPNum and math.abs(pNum - ctPNum) <= 1 then
sameTrain = true
end
end
if sameTrain then
local entryIdValid = looksLikeValidDestinationText(trainName)
if entryIdValid then
@@ -3136,6 +3216,9 @@ local function checkIsAtStationWithCurrentTrain(trainName, destination, platform
if not looksLikeValidDestinationText(destination) then
return true
end
if hasSharedAlphaNumCode(destination, ctDest) then
return true
end
end
end
return false
@@ -3222,20 +3305,6 @@ function Main.loop()
else
platform = State.stationPlatform or "1"
end
local preCorrected = tryCorrectUpcomingEntryWithCurrentTrain({
trainName = trainName,
dest = destination,
platform = platform
})
if preCorrected then
if preCorrected.trainName and tostring(preCorrected.trainName) ~= tostring(trainName) then
trainName = preCorrected.trainName
end
if preCorrected.dest and tostring(preCorrected.dest) ~= tostring(destination) then
destination = preCorrected.dest
end
end
if isStationDestination(destination) then
local cancelled = false
@@ -3261,6 +3330,21 @@ function Main.loop()
local etaTicks = realArrival - currentTick
local etaSeconds = etaTicks / (State.tickRate or 20)
if etaSeconds < 0 then etaSeconds = 0 end
local preCorrected = tryCorrectUpcomingEntryWithCurrentTrain({
trainName = trainName,
dest = destination,
platform = platform
}, etaSeconds)
if preCorrected then
if preCorrected.trainName and tostring(preCorrected.trainName) ~= tostring(trainName) then
trainName = preCorrected.trainName
end
if preCorrected.dest and tostring(preCorrected.dest) ~= tostring(destination) then
destination = preCorrected.dest
end
end
local announceKey = normalizeUpcomingKey(trainName, destination)
local etaLabel = buildEtaLabel(etaSeconds, etaTextByKey[announceKey])
@@ -3382,25 +3466,8 @@ function Main.loop()
if not tName then
platform, etaStr, tName, dest = string.match(cleanLine, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$")
end
local entryPlatform = platform or State.stationPlatform or "1"
local preCorrectedCT = tryCorrectUpcomingEntryWithCurrentTrain({
trainName = tName or "",
dest = dest or "",
platform = entryPlatform
})
if preCorrectedCT then
if preCorrectedCT.trainName and tostring(preCorrectedCT.trainName) ~= tostring(tName or "") then
tName = preCorrectedCT.trainName
end
if preCorrectedCT.dest and tostring(preCorrectedCT.dest) ~= tostring(dest or "") then
dest = preCorrectedCT.dest
end
end
if tName and etaStr and isStationDestination(dest) then
local announceKey = normalizeUpcomingKey(tName, dest)
local etaSeconds = -1
local isNow = string.find(etaStr, "现在")
@@ -3426,6 +3493,23 @@ function Main.loop()
end
end
local entryPlatform = platform or State.stationPlatform or "1"
local preCorrectedCT = tryCorrectUpcomingEntryWithCurrentTrain({
trainName = tName or "",
dest = dest or "",
platform = entryPlatform
}, etaSeconds >= 0 and etaSeconds or 0)
if preCorrectedCT then
if preCorrectedCT.trainName and tostring(preCorrectedCT.trainName) ~= tostring(tName or "") then
tName = preCorrectedCT.trainName
end
if preCorrectedCT.dest and tostring(preCorrectedCT.dest) ~= tostring(dest or "") then
dest = preCorrectedCT.dest
end
end
local announceKey = normalizeUpcomingKey(tName, dest)
table.insert(newUpcoming, {
trainName = tName,
dest = dest,
@@ -3511,7 +3595,7 @@ function Main.loop()
for _, entry in ipairs(newUpcoming) do
tryCorrectUpcomingEntryWithCurrentTrain(entry)
tryCorrectUpcomingEntryWithCurrentTrain(entry, entry.eta)
end
State.upcomingTrains = newUpcoming