Bir bash ayracı genişletmesini genişlet


20

Çoğunlukla tarihsel nedenlerden ötürü, bash, sözdizimi ve programlama paradigmalarının oldukça yoğun bir podgesidir - bu, garip ve bazen golf oynamak için sinir bozucu olabilir. Diller. Bunlardan biri küme ayracı genişlemesidir .

İki temel küme ayracı genişletme türü vardır:

  • Liste parantezleri, rastgele dizelerin virgülle ayrılmış listelerini içerebilir (kopyalar ve boş dize dahil). Örneğin {a,b,c,,pp,cg,pp,}, genişler a b c pp cg pp(boş dizelerin etrafındaki boşluklara dikkat edin).
  • Dizi parantezleri, ile ayrılmış dizi uç noktaları içerebilir ... İsteğe bağlı olarak başka ..bir adım ve ardından bir adım boyutu gelebilir. Dizi bitiş noktaları, tamsayılar veya karakterler olabilir. Sekans, hangi uç noktasının daha büyük olduğuna göre otomatik olarak yükselir veya alçalır. Örneğin:
    • {0..15} genişleyecek 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    • {-10..-5} genişleyecek -10 -9 -8 -7 -6 -5
    • {3..-6..2} genişleyecek 3 1 -1 -3 -5
    • {a..f} genişleyecek a b c d e f
    • {Z..P..3} genişleyecek Z W T Q

Bunun ötesinde, liste ayraçları ile sıra ve liste ayraçları bulunabilir:

  • {a,b,{f..k},p} genişleyecek a b f g h i j k p
  • {a,{b,c}} genişleyecek a b c

Parantezler, her iki tarafında da boşluk olmayan dizelerle genişler. Örneğin:

  • c{a,o,ha,}t genişleyecek cat cot chat ct

Bu, birlikte bir araya getirilmiş birden çok parantez için de geçerlidir:

  • {ab,fg}{1..3} genişleyecek ab1 ab2 ab3 fg1 fg2 fg3

Bu oldukça karmaşık olabilir. Örneğin:

  • {A..C}{x,{ab,fg}{1..3},y,} genişleyecek Ax Aab1 Aab2 Aab3 Afg1 Afg2 Afg3 Ay A Bx Bab1 Bab2 Bab3 Bfg1 Bfg2 Bfg3 By B Cx Cab1 Cab2 Cab3 Cfg1 Cfg2 Cfg3 Cy C

Ancak, açılımlar arasında boşluk varsa, sadece ayrı açılımlar olarak genişlerler. Örneğin:

  • {a..c} {1..5} genişleyecek a b c 1 2 3 4 5

Siparişin her zaman nasıl korunduğuna dikkat edin.


Bu meydan okuma için girişler yukarıda açıklandığı gibi bas parantez genişletmelerini genişletecektir. Özellikle:

  • tarafından değerlendirmeye bash(veya benzer genişleme yapan diğer mermilere) izin verilmez
  • sıralı parantezler her zaman sayıdan sayıya, küçük harfe küçük harfe veya büyük harfe büyük harfe dönüşmez. Sayılar, 32 bit işaretli aralıkta tamsayılar olacaktır. Verilirse, isteğe bağlı adım boyutu her zaman pozitif bir tamsayı olacaktır. (Bash'in de genişleyeceğini unutmayın {A..z}, ancak bu meydan okuma için bu göz ardı edilebilir)
  • liste parantezlerindeki tek tek öğeler her zaman yalnızca büyük ve küçük harf alfasayısal karakterlerden oluşur (boş dize dahil)
  • liste parantezleri diğer küme ayracı genişletmelerinin keyfi yuvalarını içerebilir
  • kaşlı ayraçlar keyfi sayıda kez birleştirilebilir. Bu, dilinizin hafızasıyla sınırlandırılacaktır, bu nedenle beklenti, teorik olarak rastgele sayıda birleştirmeler yapabilmenizdir, ancak size karşı saymayacak bir belleğiniz varsa / bittiğinde.

Yukarıdaki metindeki örnekler test senaryoları olarak kullanılmıştır. Özetle, her girdi satırı aynı çıktı satırına karşılık gelir, bunlar:

Giriş

{0..15}
{-10..-5}
{3..-6..2}
{a..f}
{Z..P..3}
{a,b,{f..k},p}
{a,{b,c}}
c{a,o,ha,}t
{ab,fg}{1..3}
{A..C}{x,{ab,fg}{1..3},y,}
{a..c} {1..5}
{a{0..100..10},200}r

Çıktı

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
-10 -9 -8 -7 -6 -5
3 1 -1 -3 -5
a b c d e f
Z W T Q
a b f g h i j k p
a b c
cat cot chat ct
ab1 ab2 ab3 fg1 fg2 fg3
Ax Aab1 Aab2 Aab3 Afg1 Afg2 Afg3 Ay A Bx Bab1 Bab2 Bab3 Bfg1 Bfg2 Bfg3 By B Cx Cab1 Cab2 Cab3 Cfg1 Cfg2 Cfg3 Cy C
a b c 1 2 3 4 5
a0r a10r a20r a30r a40r a50r a60r a70r a80r a90r a100r 200r

3
Bunu inceledim ve tüm kenar vakalar nedeniyle ayrıştırmak bir acı :-(
Neil

Yanıtlar:


3

Yakut, 405 403 401 400 bayt

Bilge bir adam (Jamie Zawinski) bir keresinde, "Bazı insanlar bir sorunla karşılaştıklarında 'Biliyorum, düzenli ifadeler kullanacağım' diye düşünüyorlardı. Şu an iki problemleri var."

Bu sorunu özyinelemeli regex ile çözmeye çalışana kadar bu teklifi tam olarak takdir ettiğimi sanmıyorum. Başlangıçta, regex vakaları, köşeli parantezlere bitişik harfleri içeren kenar davalarıyla uğraşmak zorunda kalana kadar basit görünüyordu ve sonra cehennemde olduğumu biliyordum.

Her neyse, burada test senaryoları ile çevrimiçi çalıştırın

->s{s.gsub!(/{(-?\w+)..(-?\w+)(..(\d+))?}/){x,y=$1,$2;a,b,c=[x,y,$4].map &:to_i
$1[/\d/]?0:(a,b=x,y)
k=a<b ?[*a..b]:[*b..a].reverse
?{+0.step(k.size-1,$4?c:1).map{|i|k[i]}*?,+?}}
r=1
t=->x{x[0].gsub(/^{(.*)}$/){$1}.scan(/(({(\g<1>|,)*}|[^,{}]|(?<=,|^)(?=,|$))+)/).map{|i|i=i[0];i[?{]?r[i]:i}.flatten}
r=->x{i=x.scan(/({(\g<1>)*}|[^{} ]+)/).map(&t)
i.shift.product(*i).map &:join}
s.split.map(&r)*' '}

Ungolfed:

->s{
  s.gsub!(/{(-?\w+)..(-?\w+)(..(\d+))?}/){  # Replace all range-type brackets {a..b..c}
    x,y=$1,$2;a,b,c=[x,y,$4].map &:to_i     # Set up int variables
    $1[/\d/]?0:(a,b=x,y)                    # Use int variables for a,b if they're numbers
    k=a<b ?[*a..b]:[*b..a].reverse          # Create an array for the range in the correct direction
    '{'+                                    # Return the next bit surrounded by brackets
      0.step(k.size-1,$4?c:1).map{|i|k[i]   # If c exists, use it as the step size for the array
      }*','                                 # Join with commas
      +'}'
  }
  r=1                                       # Dummy value to forward-declare the parse function `r`
  t=->x{                                    # Function to parse a bracket block
    x=x[0].gsub(/^{(.*)}$/){$1}             # Remove outer brackets if both are present
                                            # x[0] is required because of quirks in the `scan` function
    x=x.scan(/(({(\g<1>|,)*}|[^,{}]|(?<=,|^)(?=,|$))+)/)
                                            # Regex black magic: collect elements of outer bracket
    x.map{|i|i=i[0];i[?{]?r[i]:i}.flatten   # For each element with brackets, run parse function
  }
  r=->x{                                    # Function to parse bracket expansions a{b,c}{d,e}
    i=x.scan(/({(\g<1>)*}|[^{} ]+)/)        # Regex black magic: scan for adjacent sets of brackets
    i=i.map(&t)                             # Map all elements against the bracket parser function `t`
    i.shift.product(*i).map &:join          # Combine the adjacent sets with cartesian product and join them together
  }
  s.split.map(&r)*' '                       # Split on whitespace, parse each bracket collection
                                            #   and re-join with spaces
}

2

Python 2.7, 752 728 bayt

Vay canına, bu bir meydan okumada bir sürü kod golfü gibi!

Bir lambda kısalttığı için @Neil'e teşekkürler

def b(s,o,p):
 t,f=s>':'and(ord,chr)or(int,str);s,o=t(s),t(o);d=cmp(o,s)
 return list(map(f,range(s,o+d,int(p)*d)))
def e(s):
 c=1;i=d=0
 while c:d+=-~'{}}'.count(s[i])%3-1;i+=1;c=i<len(s)and 0<d
 return i
def m(s):
 if len(s)<1:return[]
 if','==s[-1]:return m(s[:-1])+['']
 i=0
 while i<len(s)and','!=s[i]:i+=e(s[i:])
 return[s[:i]]+m(s[i+1:])
n=lambda a,b:[c+d for c in a for d in b]or a or b
def p(s):
 h=s.count
 if h('{')<1:return[s]
 f,l=s.index('{'),e(s)
 if h('{')<2and h('..')>0and f<1:s=s[1:-1].split('..');return b(s[0],s[1],s[2])if len(s)>2 else b(s[0],s[1],1)
 if f>0 or l<len(s):return n(p(s[:f]),n(p(s[f:l]),p(s[l:])))
 return sum(map(list,map(p,m(s[1:-1]))),[])
o=lambda s:' '.join(p('{'+s.replace(' ',',')+'}'))

açıklama

  • b: aralığı özelliklerine göre hesaplar.
  • e: en dıştaki en yakın küme ayracı konumunu döndürür. İteratif.
  • m: en dıştaki öğeleri virgüllere ayırır. Recursive.
  • n: boşluğu kontrol ederken dizileri birleştirir. Ben alamadım and/orişe.
  • p: İşlerin çoğunun yapıldığı yer. Tüm vakaları kontrol eder (Aralık, sadece liste, birleştirmek gerekir). Recursive.
  • o: Girdi ne almalı. Girdi / çıktıyı biçimlendirir p.

Bazı yerlerde gelişebileceğimi hissediyorum, bu yüzden daha fazla golf yapmaya çalışacağım. Ayrıca açıklamada daha ayrıntılı olarak anlatmalıyım.


Ben umuyordum [c+d for c in a for d in b] or a or bişe.
Neil

2

JavaScript (Firefox 30-57), 465 427 425 bayt

f=s=>/\{/.test(s)?f(s.replace(/([^,{}]*\{[^{}]*\})+[^,{}]*/,t=>t.split(/[{}]+/).map(u=>u.split`,`).reduce((a,b)=>[for(c of a)for(d of b)c+d]))):s.split`,`.join` `
s=>f(`{${s.split` `}}`.replace(/\{(-?\w+)\.\.(-?\w+)(\.\.(\d+))?\}/g,(m,a,o,_,e)=>{m=(a>'@')+(a>'_');a=parseInt(a,m?36:10);o=parseInt(o,m?36:10);e=+e||1;if(o<a)e=-e;for(r=[];e<0?o<=a:a<=o;a+=e)r.push(m?a.toString(36):a);r=`{${r}}`;return m-1?r:r.toUpperCase()}))

ES6 sürümü, f10 bayt ağırlığındadır:

f=s=>/\{/.test(s)?f(s.replace(/([^,{}]*\{[^{}]*\})+[^,{}]*/,t=>t.split(/[{}]+/).map(u=>u.split`,`).reduce((a,b)=>[].concat(...a.map(c=>b.map(d=>c+d)))))):s.split`,`.join` `
g=s=>f(`{${s.split` `}}`.replace(/\{(-?\w+)\.\.(-?\w+)(\.\.(\d+))?\}/g,(m,a,o,_,e)=>{m=(a>'@')+(a>'_');a=parseInt(a,m?36:10);o=parseInt(o,m?36:10);e=+e||1;if(o<a)e=-e;for(r=[];e<0?o<=a:a<=o;a+=e)r.push(m?a.toString(36):a);r=`{${r}}`;return m-1?r:r.toUpperCase()}))
h=(s,t=s.replace(/\{[^{}]*\}/,""))=>s!=t?h(t):!/[{}]/.test(s)
<input oninput="o.textContent=h(this.value)?g(this.value):'{Invalid}'"><div id=o>

Açıklama: Boşlukları virgülle değiştirerek ve tüm dizeyi {}tutarlılık için sararak başlar (fikir için @Mavi sayesinde). Sonra tüm {..}yapıları arar ve yapılara genişletir {,}. Daha sonra, tüm {,}yapıları içeriden dışarıya tekrar tekrar genişletmek için özyineleme kullanır . Sonunda tüm virgüllerin yerini boşluk alır.

f=s=>/\{/.test(s)?                  while there are still {}s
 f(s.replace(                       recursive replacement
  /([^,{}]*\{[^{}]*\})+[^,{}]*/,    match the deepest group of {}s
  t=>t.match(/[^{}]+/g              split into {} terms and/or barewords
   ).map(u=>u.split`,`              turn each term into an array
   ).reduce((a,b)=>                 loop over all the arrays
    [for(c of a)for(d of b)c+d]))   cartesian product
  ):s.split`,`.join` `              finally replace commas with spaces
s=>f(                               change spaces into commas and wrap
 `{${s.split` `}}`.replace(         match all {..} seqences
   /\{([-\w]+)\.\.([-\w]+)(\.\.(\d+))?\}/g,(m,a,o,_,e)=>{
    m=(a>'@')+(a>'_');              sequence type 0=int 1=A-Z 2=a-z
    a=parseInt(a,m?36:10);          convert start to number
    o=parseInt(o,m?36:10);          convert stop to number
    e=+e||1;                        convert step to number (default 1)
    if(o<a)e=-e;                    check if stepping back
    for(r=[];e<0?o<=a:a<=o;a+=e)    loop over each value
     r.push(m?a.toString(36):a);    convert back to string
    r=`{${r}}`;                     join together and wrap in {}
    return m-1?r:r.toUpperCase()})) convert type 1 back to upper case
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.