def compare_semver(a, b):
    def parse(v):
        parts = v.split('-', 1)
        nums = parts[0].split('.')
        major, minor, patch = int(nums[0]), int(nums[1]), int(nums[2])
        prerelease = parts[1] if len(parts) > 1 else None
        return (major, minor, patch, prerelease)

    def compare_prerelease(pa, pb):
        if pa is None and pb is None:
            return 0
        if pa is None:
            return 1  # release > prerelease
        if pb is None:
            return -1
        ids_a = pa.split('.')
        ids_b = pb.split('.')
        for ia, ib in zip(ids_a, ids_b):
            a_num = ia.isdigit()
            b_num = ib.isdigit()
            if a_num and b_num:
                na, nb = int(ia), int(ib)
                if na != nb:
                    return -1 if na < nb else 1
            elif a_num and not b_num:
                return -1  # numeric < alphanumeric
            elif not a_num and b_num:
                return 1
            else:
                if ia != ib:
                    return -1 if ia < ib else 1
        if len(ids_a) != len(ids_b):
            return -1 if len(ids_a) < len(ids_b) else 1
        return 0

    pa, pb = parse(a), parse(b)
    for i in range(3):
        if pa[i] != pb[i]:
            return -1 if pa[i] < pb[i] else 1
    return compare_prerelease(pa[3], pb[3])
