class ChapterRecognition { final _numberPattern = r"([0-9]+)(\.[0-9]+)?(\.?[a-z]+)?"; final _unwanted = RegExp(r"\b(?:v|ver|vol|version|volume|season|s)[^a-z]?[0-9]+"); final _unwantedWhiteSpace = RegExp(r"\s(?=extra|special|omake)"); int parseChapterNumber(String mangaTitle, String chapterName) { var name = chapterName.toLowerCase(); name = name.replaceAll(mangaTitle.toLowerCase(), "").trim(); name = name.replaceAll(',', '.').replaceAll('-', '.'); name = name.replaceAll(_unwantedWhiteSpace, ""); name = name.replaceAll(_unwanted, ""); final numberPat = "*$_numberPattern"; const ch = r"(?<=ch\.)"; var match = RegExp("$ch $numberPat").firstMatch(name); if (match != null) { return _getChapterNumberFromMatch(match).toInt(); } match = RegExp(_numberPattern).firstMatch(name); if (match != null) { return _getChapterNumberFromMatch(match).toInt(); } return 0; } double _getChapterNumberFromMatch(Match match) { final initial = double.parse(match.group(1)!); final subChapterDecimal = match.group(2); final subChapterAlpha = match.group(3); final addition = _checkForDecimal(subChapterDecimal, subChapterAlpha); return initial + addition; } double _checkForDecimal(String? decimal, String? alpha) { if (decimal != null && decimal.isNotEmpty) { return double.parse(decimal); } if (alpha != null && alpha.isNotEmpty) { if (alpha.contains("extra")) { return 0.99; } if (alpha.contains("omake")) { return 0.98; } if (alpha.contains("special")) { return 0.97; } final trimmedAlpha = alpha.replaceFirst('.', ''); if (trimmedAlpha.length == 1) { return _parseAlphaPostFix(trimmedAlpha[0]); } } return 0.0; } double _parseAlphaPostFix(String alpha) { final number = alpha.codeUnitAt(0) - ('a'.codeUnitAt(0) - 1); if (number >= 10) return 0.0; return number / 10.0; } }