Regex (sapore PCRE), 66 (65🐌) byte
Ispirato dal vedere che sia Martin Ender che jaytea , due geni della regex, scrissero soluzioni regex a questo codice golf, ne scrissi la mia da zero. Il famoso regex a controllo di prim'ordine non appare da nessuna parte nella mia soluzione.
Non leggerlo se non vuoi che qualche magia regex unaria venga rovinata per te. Se vuoi provare a capire da solo questa magia, ti consiglio vivamente di iniziare risolvendo alcuni problemi nella regex di ECMAScript:
- Abbina i numeri primi (se non hai già familiarità con questo in regex)
- Abbina poteri di 2 (se non l'hai già fatto). O semplicemente fatti strada attraverso Regex Golf , che include Prime e Powers. Assicurati di eseguire i set di problemi sia Classic che Teukon.
Trova il modo più breve per abbinare i poteri di N dove N è una costante (cioè specificata nella regex, non nell'input) che può essere composita (ma non è richiesta). Ad esempio, abbina poteri di 6.
Trova un modo per abbinare l'ennesimo potere, dove N è una costante> = 2. Ad esempio, abbina i quadrati perfetti. (Per un riscaldamento, abbina i poteri principali .)
Abbina le dichiarazioni di moltiplicazione corrette. Abbina i numeri triangolari.
Abbina i numeri di Fibonacci (se sei pazzo come me) o se vuoi attenersi a qualcosa di più breve, abbina le giuste dichiarazioni di esponenziazione (per un riscaldamento, ritorna come un logaritmo in base 2 di una potenza di 2 - bonus, fai lo stesso per qualsiasi numero, arrotondandolo come preferisci) o numeri fattoriali (per un riscaldamento, abbina i numeri primari ).
Abbina numeri abbondanti (se sei pazzo come me)
Calcola un numero irrazionale con la precisione richiesta (ad esempio dividi l'input per la radice quadrata di 2, restituendo il risultato arrotondato come una corrispondenza)
(Il motore regex che ho scritto può essere di aiuto, poiché è molto veloce nelle regex matematiche unarie e include una modalità numerica unaria che può testare intervalli di numeri naturali (ma ha anche una modalità stringhe che può valutare regex non unari o unaria con delimitatori). Per impostazione predefinita è compatibile con ECMAScript, ma ha estensioni opzionali (che possono aggiungere selettivamente sottoinsiemi di PCRE, o persino lookahead molecolare, qualcosa che nessun altro motore regex ha).)
Altrimenti, continua a leggere e leggi anche questo GitHub Gist (avvertimento, molti spoiler) che racconta il viaggio della spinta alla regex di ECMAScript per affrontare le funzioni numeriche naturali di crescente difficoltà (a partire dal set di puzzle di Teukon, non tutti matematici, che hanno scatenato questo viaggio).
Come con le altre soluzioni regex a questo problema, l'input è dato come due numeri in unario biiettivo, separati da una virgola, che rappresentano un intervallo inclusivo. Viene restituito un solo numero. La regex potrebbe essere modificata per restituire tutti i numeri che condividono lo stesso fattore primo più grande più piccolo, come corrispondenze separate, ma ciò richiederebbe un lookbebe a lunghezza variabile e inserendo \K
un lookahead o restituendo il risultato come una cattura anziché una corrispondenza.
La tecnica usata qui di ripetuta divisione implicita per il fattore primo più piccolo è identica a quella usata nelle stringhe Match la cui lunghezza è una quarta risposta di potenza che ho postato qualche tempo fa.
Senza ulteriori indugi:
((.+).*),(?!.*(?=\1)(((?=(..+)(\5+$))\6)*)(?!\2)).*(?=\1)\K(?3)\2$
Puoi provarlo qui.
E la versione a spaziatura libera, con commenti:
# No ^ anchor needed, because this algorithm always returns a
# match for valid input (in which the first number is less than
# or equal to the second number), and even in /g mode only one
# match can be returned. You can add an anchor to make it reject
# invalid ranges.
((.+).*), # \1 = low end of range; \2 = conjectured number that is the
# smallest number in the set of the largest prime factor of each
# number in the range; note, it is only in subsequent tests that
# this is implicitly confined to being prime.
# We shall do the rest of our work inside the "high end of range"
# number.
(?! # Assert that there is no number in the range whose largest prime
# factor is smaller than \2.
.*(?=\1) # Cycle tail through all numbers in the range, starting with \1.
( # Subroutine (?3):
# Find the largest prime factor of tail, and leave it in tail.
# It will both be evaluated here as-is, and later as an atomic
# subroutine call. As used here, it is not wrapped in an atomic
# group. Thus after the return from group 3, backtracking back
# into it can increase the value of tail – but this won't mess
# with the final result, because only making tail smaller could
# change a non-match into a match.
( # Repeatedly divide tail by its smallest prime factor, leaving
# only the largest prime factor at the end.
(?=(..+)(\5+$)) # \6 = tool to make tail = \5 = largest nontrivial factor of
# current tail, which is implicitly the result of dividing it
# by its smallest prime factor.
\6 # tail = \5
)*
)
(?!\2) # matches iff tail < \ 2
)
# now, pick a number in the range whose largest prime factor is \2
.*(?=\1) # Cycle tail through all numbers in the range, starting with \1.
\K # Set us up to return tail as the match.
(?3) # tail = largest prime factor of tail
\2$ # Match iff tail == \2, then return the number whose largest
# prime factor is \2 as the match.
L'algoritmo può essere facilmente trasferito su ECMAScript sostituendo la chiamata della subroutine con una copia della subroutine e restituendo la corrispondenza come gruppo di acquisizione anziché utilizzare \ K. Il risultato è di 80 byte di lunghezza:
((x+)x*),(?!.*(?=\1)((?=(xx+)(\4+$))\5)*(?!\2)).*(?=\1)(((?=(xx+)(\8+$))\9)*\2$)
Provalo online!
Si noti che ((.+).*)
può essere modificato in ((.+)+)
, diminuendo la dimensione di 1 byte (da 66 a 65 byte ) senza perdita della funzionalità corretta - ma il regex esplode esponenzialmente con lentezza.
Provalo online! (79 byte ECMAScript versione esponenziale-rallentamento)