def eval_repetition(texts, n=4, threshold=0.3):
if n < 1:
raise ValueError("n must be >= 1")
def rep_rate(s):
total = len(s) - n + 1
if total <= 0:
return 0.0
grams = {s[i:i + n] for i in range(total)}
return round((total - len(grams)) / total, 4)
def longest_dup(s):
best = 0
for L in range(1, len(s)):
seen = set()
hit = False
for i in range(len(s) - L + 1):
sub = s[i:i + L]
if sub in seen:
hit = True
break
seen.add(sub)
if not hit:
break
best = L
return best
details = [{"index": i, "rep_rate": rep_rate(t), "max_dup_len": longest_dup(t)}
for i, t in enumerate(texts)]
bad = [d["index"] for d in details if d["rep_rate"] >= threshold]
avg = round(sum(d["rep_rate"] for d in details) / len(details), 4) if details else 0.0
worst = max(details, key=lambda d: d["rep_rate"])["index"] if details else -1
return {"avg_rate": avg, "worst": worst, "bad_count": len(bad),
"bad_index": bad, "details": details}
from collections import Counter
def rep_rate_v2(s, n=4):
total = len(s) - n + 1
if total <= 0:
return 0.0
c = Counter(s[i:i + n] for i in range(total))
return round(sum(v - 1 for v in c.values()) / total, 4)
def longest_dup_v2(s):
def has_dup(L):
if L <= 0:
return False
seen = set()
for i in range(len(s) - L + 1):
sub = s[i:i + L]
if sub in seen:
return True
seen.add(sub)
return False
lo, hi = 0, max(0, len(s) - 1)
while lo < hi:
mid = (lo + hi + 1) // 2
if has_dup(mid):
lo = mid
else:
hi = mid - 1
return lo
def eval_repetition_v2(texts, n=4, threshold=0.3):
if n < 1:
raise ValueError("n must be >= 1")
details = [{"index": i, "rep_rate": rep_rate_v2(t, n), "max_dup_len": longest_dup_v2(t)}
for i, t in enumerate(texts)]
bad = [d["index"] for d in details if d["rep_rate"] >= threshold]
avg = round(sum(d["rep_rate"] for d in details) / len(details), 4) if details else 0.0
worst = max(range(len(details)), key=lambda i: details[i]["rep_rate"]) if details else -1
return {"avg_rate": avg, "worst": worst, "bad_count": len(bad), "bad_index": bad,
"details": details}
def longest_dup_suffix(s):
if len(s) < 2:
return 0
sa = sorted(range(len(s)), key=lambda i: s[i:])
best = 0
for a, b in zip(sa, sa[1:]):
k = 0
while k < min(len(s) - a, len(s) - b) and s[a + k] == s[b + k]:
k += 1
best = max(best, k)
return best