Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,45 @@ internal object DimensionCleaner : ValueCleaner {
private val matchKeywords = setOf("match", "parent")
private val wrapKeywords = setOf("wrap", "content", "wrapcan")
private val DIMENSION_CONSTANTS = listOf("wrap_content", "match_parent")
private val explicitDimensionRegex = Regex("^(-?\\d+)(dp|sp|px|dip)$")

override fun clean(rawValue: String): String {
val normalized = rawValue.lowercase().replace(" ", "_")
val trimmedValue = rawValue.trim()
val normalized = trimmedValue.lowercase().replace(" ", "_")

if (matchKeywords.any { it in normalized }) return "match_parent"
if (wrapKeywords.any { it in normalized }) return "wrap_content"

val fuzzyResult = FuzzySearch.extractOne(normalized, DIMENSION_CONSTANTS)
if (fuzzyResult.score >= 60) return fuzzyResult.string

val fixedUnit = normalized.replace(Regex("0p$|op$|olp$"), "dp")
explicitDimensionRegex.matchEntire(fixedUnit)?.let { match ->
val normalizedNumber = normalizeOcrDimensionNumber(match.groupValues[1])
return normalizedNumber + match.groupValues[2]
}

val numericPart = NumberCleaner.clean(fixedUnit.replace("_", ""))
val normalizedNumericPart = normalizeOcrDimensionNumber(numericPart)

return if (numericPart != fixedUnit) "${normalizedNumericPart}dp" else trimmedValue
}

private fun normalizeOcrDimensionNumber(numericPart: String): String {
if (!numericPart.matches(Regex("-?\\d+"))) return numericPart

val isNegative = numericPart.startsWith("-")
val numericValue = numericPart.toLongOrNull() ?: return numericPart
val canonical = numericValue.toString()
val unsignedCanonical = canonical.removePrefix("-")

// OCR sometimes reads the trailing "dp" as a single zero, turning 150dp into 1500.
if (unsignedCanonical.endsWith('0') && unsignedCanonical.toLong() >= 1000L) {
val normalizedValue = numericValue / 10L
return normalizedValue.toString()
}

return if (numericPart != fixedUnit) "${numericPart}dp" else rawValue
return if (isNegative && numericValue == 0L) "0" else canonical
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,30 @@ class FuzzyAttributeParserTest {
assertEquals("wrap_content", result["android:layout_height"])
}

@Test
fun `OCR dimension with trailing zero before dp is normalized`() {
val annotation = "height: 1500dp | width: 100dp"
val result = FuzzyAttributeParser.parse(annotation, "EditText")

assertEquals("150dp", result["android:layout_height"])
}

@Test
fun `zero padded dimension values are normalized`() {
val annotation = "height: 0010dp | width: 100dp"
val result = FuzzyAttributeParser.parse(annotation, "EditText")

assertEquals("10dp", result["android:layout_height"])
}

@Test
fun `all zero padded dimension values normalize to zero`() {
val annotation = "height: 0000dp | width: 100dp"
val result = FuzzyAttributeParser.parse(annotation, "EditText")

assertEquals("0dp", result["android:layout_height"])
}

@Test
fun `empty chunks between pipes are skipped`() {
val annotation = "width: 100dp | | height: 80dp"
Expand Down
Loading