解码字符串


41

这是我对ppcg的第一个挑战!

输入项

由两个不同的ASCII字符组成的字符串。例如

ABAABBAAAAAABBAAABAABBAABA

挑战

任务是按照以下规则解码此字符串:

  1. 跳过前两个字符
  2. 将字符串的其余部分分成8个字符的组
  3. 在每个组中,0如果该字符与原始字符串的第一个字符相同,则替换为每个字符,1否则为
  4. 现在每个组代表一个字节。将每个组从字节字符代码转换为字符
  5. 连接所有字符

让我们解码上面的字符串。

 AB  AABBAAAA  AABBAAAB  AABBAABA
 ^^     ^         ^         ^
 |      |         |         |
 |      \---------|---------/
 |                |
Skip      Convert to binary

请注意,这A是原始字符串中的第一个字符,B第二个字符。因此,替换每个A0每个B1。现在我们获得:

00110000  00110001  00110010

这是[0x30, 0x31, 0x32]二进制的。这些值["0", "1", "2"]分别表示字符,因此最终输出应为012

计分

当然,这是,这意味着使您的代码尽可能短。分数以字节为单位。

约束和IO格式

适用标准规则。以下是一些其他规则:

  • 您可以假设输入有效
    • 输入字符串完全由两个不同的字符组成
    • 前两个字符不同
    • 输入字符串的最小长度为2个字符
    • 长度将始终为2模8
  • 您可以假设该字符串将始终仅由可打印的ASCII字符组成
    • 在输入和在解码的字符串中
  • 输出中允许前导和尾随空格(所有与匹配的内容/\s*/

5
得说,对于第一个挑战,这是我见过的格式更好的挑战之一。作为风云人物,社区沙箱是在发布之前进行反馈的好地方,因此您不会因自己不认识的规则而遭到随机代表轰炸。
魔术章鱼缸

@MagicOctopusUrn。谢谢!不知道沙盒,我下次再发布:)

2
我主要使用它,以便人们可以在重复的问题上叫我,很容易遵循规则,而在不记住meta :)的情况下很难了解重复。我还建议您查看聊天室,我们为几乎所有您希望学习的语言进行了聊天,并鼓励您提出问题。
魔术章鱼缸

1
伟大的第一个挑战!还有更多的测试用例会很整洁。
林恩

真的很好,第一个挑战。玩这个很开心。
ElPedro '18 -4-23

Answers:



8

Stax15 11 字节

ó║¥U⌂½íèäöñ

在staxlang.xyz上运行和调试它!

快速的'n'肮脏的方法。致力于改进。改进了!

解压缩(13个字节)和说明

2:/8/{{[Im:bm
2:/              Split at index 2. Push head, then tail.
   8/            Split into length-8 segments.
     {      m    Map block over each segment:
      {  m         Map block over each character:
       [             Copy first two elements (below) in-place.
        I            Index of character in first two characters.
          :b       Convert from binary.
                 Implicit print as string.

啊...我知道这会打败我们。
魔术章鱼缸

6

JavaScript(Node.js),67字节

s=>s.replace(/./g,x=(c,i)=>(x=x*2|c==s[1],Buffer(i<3|i&7^1?0:[x])))

在线尝试!

怎么样?

我们使用Buffer构造函数的两种不同语法:

  • Buffer([n])生成一个包含唯一字节n的缓冲区,并被强制转换为相应的ASCII字符。仅考虑n的8个最低有效位。
  • Buffer(n)生成一个n字节的缓冲区。因此,Buffer(0)生成一个空缓冲区,将其强制为一个空字符串。

注意:两者在最新的Node版本中均已弃用。Buffer.from([n])并且Buffer.alloc(n)应改为使用。

已评论

s =>                   // given the input string s
  s.replace(/./g, x =  // initialize x to a non-numeric value (will be coerced to 0)
    (c, i) => (        // for each character c at position i in s:
      x = x * 2 |      //   shift x to the left
          c == s[1],   //   and append the new bit, based on the comparison of c with s[1]
      Buffer(          //   invoke the constructor of Buffer (see above):
        i < 3 |        //     if i is less than 3
        i & 7 ^ 1 ?    //     or i is not congruent to 1 modulo 8:
          0            //       replace c with an empty string
        :              //     else:
          [x]          //       replace c with the ASCII char. whose code is the LSB of x
      )                //   end of Buffer constructor
  ))                   // end of replace(); return the new string

6

bash,59 58 52字节

tr -t "$1" 01 <<<$1|cut -c3-|fold -8|sed 'i2i
aP'|dc

在线尝试!

感谢Cows quack节省了6个字节。

这个挑战对于一系列coreutils来说非常有效(并dc在最后进行转换和输出)。首先,我们使用

tr -t "$1" 01 <<<$1

将输入中的两个字符音译为零和一。该-t标志将第一个参数截断为第二个参数的长度,因此这减少了音译为0和的输入中的前两个字符1,这就是我们想要的。然后,

cut -c3-

删除前两个字符,并

fold -8

每行输出8个字符。最后,该sed命令将每一行变成一个dc片段,该片段将数字读取为二进制并输出该字节。


总是很高兴看到bash的答案:)您可以使用sed来简化dc计算,方法是将每行转换为打印出每个字符的dc代码,然后在dctio.run/##S0oszvj/…中评估它(以及cut -c可以删除之后的空间)
Kritixi Lithos '18

6

Amstrad CPC上的Z80机器代码,32 31 30字节

000001  0000  (9000)        ORG &9000
000002  9000  EB            EX DE, HL
000003  9001  46            LD B, (HL)
000004  9002  23            INC HL
000005  9003  5E            LD E, (HL)
000006  9004  23            INC HL
000007  9005  56            LD D, (HL)
000009  9006  1A            LD A, (DE)
000010  9007  05            DEC B
000011  9008  13            INC DE
000012  9009  4F            LD C, A
000014  900A                Light
000015  900A  26 01         LD H, &01
000016  900C                Last
000017  900C  13            INC DE
000018  900D  05            DEC B
000019  900E  C8            RET Z
000021  900F                Loop
000022  900F  1A            LD A, (DE)
000023  9010  B9            CP C
000024  9011  28 01         JR Z, Lable
000025  9013  37            SCF
000026  9014                Lable
000027  9014  ED 6A         ADC HL, HL
000028  9016  30 F4         JR NC, Last
000029  9018  7D            LD A, L
000030  9019  CD 5A BB      CALL &BB5A
000032  901C  18 EC         JR Light

该代码将指令替换为每个字符(0如果该字符与原始字符串的第一个字符相同),1否则替换为字面意义,并且不再费心检查字符是否与输入字符串中的第二个字符匹配。它只检查与第一个字符相同和与第一个字符不同的字符。

我跑寄存器(Z80的只有7个易于使用的8位寄存器,其余需要更长的指令),所以我放出来&01H,用一起L建立起来的ASCII字符(我才意识到这是不必要的初始化L,节约一个字节)。当H溢出到进位标志中时,L准备输出字符。幸运的是,有一个16位ADC广告与d Ç,做了左移位指令的作业ARRY)。

(DE)只能被读入A,尽管(HL)可以读入的任何8位寄存器,所以这是一种折衷一个要使用的。我不能比较(DE)C直接,所以我只好加载一成A第一。标签只是以L(汇编程序的要求)开头的随机单词。

  • A 累加器-唯一可以进行比较的寄存器
  • B计数寄存器用于指令DJNZd ecrement( B)和Ĵ UMP如果Ñž ERO。通过重新排列代码,我可以DJNZ减少一个字节的工作量
  • C 输入字符串中的第一个字符
  • DE作为DE当前输入字符的地址
  • H 进位触发器(每8个循环)
  • L 正在建立的输出字符

在此处输入图片说明


6

05AB1E,10个字节

¦¦Sk8ôJCçJ

在线尝试!

-3感谢emigna。


Ù             # Unique letters, in order they appear.
 v            # For each...
  yN:         # Push letter and index, replace in input.
     }        # End loop.
      ¦¦      # Remove first x2.
        8ô    # Split into eighths.
          C   # Convert to integer.
           ç  # Convert to char.
            J # Join together entire result.

1
您可以使用01‡而不是循环。编辑:甚至更好:¦¦Sk8ôJCçJ
Emigna


5

J,17 13字节

u:_8#.\2}.1{=

-4感谢FrownyFrog

旧版本:

u:_8#.\2&({.i.}.)

说明:

u:_8#.\2}.1{=
            =  | Self classify, for each unique element x of y, compute x = y, element-wise
          1{   | Second row
       2}.     | Drop 2
  _8#.\        | Convert non-intersecting subarrays of length 8 from binary
u:             | Convert to characters

例子:

   = 'ABAABBAAAAAABBAAABAABBAABA'
1 0 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 0 1 1 0 0 1 1 0 1
0 1 0 0 1 1 0 0 0 0 0 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0

   2}.1{= 'ABAABBAAAAAABBAAABAABBAABA'
0 0 1 1 0 0 0 0 0 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0

   _8#.\2}.1{= 'ABAABBAAAAAABBAAABAABBAABA'
48 49 50

   u:_8#.\2}.1{= 'ABAABBAAAAAABBAAABAABBAABA'
012

1
2}.1{=保存4个字节。
FrownyFrog

哦,天哪,绑...我找不到另一个字节。
魔术章鱼缸

1
@MagicOctopusUrn实际上是一个片段,应该[:在开始时有一个:)
FrownyFrog


5

R,71个字节

function(s)intToUtf8(2^(7:0)%*%matrix((y=utf8ToInt(s))[-1:-2]==y[2],8))

在线尝试!

出奇的高尔夫球!

首先,使用将字符串转换为ASCII代码点,并将其utf8ToInt另存为y。使用负索引删除前两个字符比使用短tail

y[-1:-2]==y[2]当应用%*%(矩阵乘法)时,该数组等效于位,但是首先我们将该数组重塑为matrixwith nrow=8,将线性数组转换为字节分组。幸运的是,我们可以使用适当的2的幂进行矩阵乘法来转换为ascii码点2^(7:0),然后使用来将码点转换回字符串intToUtf8



4

PHP,73 71字节

while($s=substr($argn,-6+$i+=8,8))echo~chr(bindec(strtr($s,$argn,10)));

与管道一起运行-nR在线尝试

打高尔夫球:

  • 在处开始索引并在处-6预先增加8
  • 漏洞利用,它strtr忽略了long参数中多余的字符(substr不需要)
  • 转换为10然后反转不需要引号-> -1字节
  • 反转字符而不是ASCII码-> ~用作字边界-> -1字节。

3
至少您应该匹配Brainfuck:for(;$s=substr($argn,2+8*$i++,8);)echo~chr(bindec(strtr($s,$argn,10)));
Christoph

2
@Christoph我喜欢Brainfuck突然成为合理答案长度的标准。
Nit

4

Pyth,20个 9字节

CittxLQQ2

多亏了FryAmTheEggman,节省了11个字节。

在这里尝试

说明

CittxLQQ2
    xLQQ    Find the index of each character in the string.
  tt        Exclude the first 2.
 i      2   Convert from binary.
C           Get the characters.

@FryAmTheEggman谢谢。显然,我对Pyth仍有很多了解。
助记符'18

哈哈,我也是!这是一种非常复杂的高尔夫语言。我希望你继续打高尔夫球:)
FryAmTheEggman '18

3

红宝石82 79字节

->s{s[2..-1].tr(s[0,2],'01').chars.each_slice(8).map{|s|s.join.to_i(2).chr}*''}

在线尝试!


1
欢迎来到PPCG!我没有看到已经有人在Ruby中的答案之前,我贴我的,但一些典型的高尔夫技巧应用到你的做法太-例如,最后.join可以被替换*'',并s[0..1]通过s[0,2]
Kirill L.

3

Japt,11个字节

¤£bXÃò8 ®Íd

试试吧


说明

¤               :Slice from the 3rd character
 £  Ã           :Map over each X
  bX            :  Get the first 0-based index of X in the input
     ò8         :Split to an array of strings of length 8
        ®       :Map
         Í      :  Convert from base-2 string to base-10 integer
          d     :  Get the character at that codepoint

非常聪明地使用了s2快捷方式,不错。
Nit

3

PHP + GNU多精度,63 61

<?=gmp_export(gmp_init(substr(strtr($argn,$argn,"01"),2),2));

遗憾的是,GMP扩展未默认激活(但已出厂)。

像这样运行:

echo "ABABABAAAAABABAAAAAABAABBAABAAAABBABAAABBB" | php -F a.php

<?=节省2个字节,并可能节省一天的时间。;-)
泰特斯(Titus),

@Titus是的,但可悲的是,它不适用于-R(我尝试过)。
Christoph

1
尝试-F代替
泰特斯


3

爪哇8,143个 142 141字节

s->{char i=47;for(;++i<50;)s=s.replace(s.charAt(i%2),i);for(i=2;i<s.length();)System.out.print((char)Long.parseLong(s.substring(i,i+=8),2));}

-1个字节感谢@OlivierGrégoire

在线尝试。

说明:

s->{                            // Method with String parameter and no return-type
  char i=47;                    //  Index character, starting at 47
  for(;++i<50;)                 //  Loop 2 times
    s.replace(s.charAt(i%2),i)  //   Replace first characters to 0, second characters to 1
  for(i=2;i<s.length();)        //  Loop `i` from 2 upwards over the String-length
    System.out.print(           //   Print:
     (char)                     //    As character:
      Long.parseLong(           //     Convert Binary-String to number
       s.substring(i,i+=8)      //      The substring in range [i,i+8),
      ,2));}



2

APL + WIN,30个字节

索引原点0。提示输入字符串

⎕av[2⊥¨(+\0=8|⍳⍴b)⊂b←2↓s≠↑s←⎕]

说明:

s≠↑s←⎕ prompts for string and creates binary vector not equal to first character

b←2↓s drops first two elements of binary

(+\0=8|⍳⍴b)⊂ splits binary into groups of 8

2⊥¨ converts each group to decimal

⎕av[...] displays decoded characters

我认为Quad-AV与APL + WIN的ASCII一致吗?
扎卡里

@Zacharý是的第一个128个字符。特殊的APL字符替换扩展的ASCII字符集中的某些字符。
格雷厄姆

2

红色,110字节

func[s][t: 0 i: 128 foreach c next next s[if c = s/2[t: t + i]i: i / 2 if i = 0[prin to-char t t: 0 i: 128]]] 

在线尝试!

说明:

一个简单直接的解决方案,没有内置函数。

f: func [s] [                      ; s is the argument (string)
    t: 0                           ; total - initially 0
    i: 128                         ; powers of 2, initially 0
    b: s/2                         ; b is the second charachter
    foreach c next next s [        ; for each char in the input string after the 2nd one
        if c = b [t: t + i]        ; if it's equal to b than add the power of 2 to t
        i: i / 2                   ; previous power of 2
        if i = 0 [                 ; if it's 0 
            prin to-char t         ; convert t to character and print it
            t: 0                   ; set t to 0
            i: 128                 ; i to 128
        ]
    ]
] 

2

Google表格,123字节

=ArrayFormula(Join("",IfError(Char(Bin2Dec(Substitute(Substitute(Mid(A1,3+8*(Row(A:A)-1),8),Left(A1),0),Mid(A1,2,1),1))),""

输入在单元格中A1。Google会自动将其添加)))到公式的末尾。

说明:

  • Mid(A1,3+8*(Row(A:A)-1),8) 从第三个字符开始一次抓取8个字符块。
  • Substitute(Mid(~),Left(A1),0) 将第一个字符的每个实例替换为0。
  • Substitute(Substitute(~),Mid(A1,2,1),1) 用1替换第二个字符。
  • Char(Bin2Dec(Substitute(~))) 将块转换为十进制,然后转换为ASCII。
  • IfError(Char(~,""))纠正所有错误,这些错误是由于Row(A:A)返回的值远远大于我们Bin2Dec给我们提供的零值和零Char误差所导致的。
  • ArrayFormula(Join("",IfError(~)))将所有Char结果结合在一起,这ArrayFormula就是使Row(A:A)返回值组成一个数组而不是第一个值的原因。




2

Python 2,88字节

i=input()
f=''.join('10'[x==i[0]]for x in i[2:])
while f:print chr(int(f[:8],2));f=f[8:]

在线尝试!

不是最短的-只是一种替代方法。

以下版本在一行上输出98字节的输出,尽管规则规定允许尾随空格。

i=input();f=''.join('10'[x==i[0]]for x in i[2:]);o=""
while f:o+=chr(int(f[:8],2));f=f[8:]
print o

在线尝试!


最终输出应该在一行上,而不是三行上。
idrougge

在OP中:“在输出中允许前导和尾随空格(与/ \ s * /匹配的所有字符)”。换行符匹配/\s*/
ElPedro '18 -4-25

1
抱歉,我不太了解正则表达式。:/
idrougge

我也不是,但我还是用谷歌搜索只是为了确保;-)
ElPedro




1

Haskell中124个 105 93字节

f(x:_:y)=fromEnum.(/=x)<$>y
g[]=[]
g s=(toEnum.sum.zipWith((*).(2^))[7,6..0])s:g(drop 8s)
g.f

在线尝试!

f通过将每个字符与第一个字符进行比较,将Bools转换为零,然后使用,将字符串转换为位列表fromEnumg划分该列表划分为8组,将它们转换为十进制数,并取所得的号码作为值Enum,这Char是的一个实例。

变化:

  • @Laikoni表示-19个字节(删除导入,嵌入map到函数中)
  • -12个字节受@Lynn的答案启发(take通过使用较短的列表进行压缩来摆脱)

2
您可以使用toEnum代替chr并删除导入。也map可以包含到中g。两者之间的空间8 s可以删除。
Laikoni '18

1

第四(gforth),83个字节

: f over c@ 0 rot 2 do 2* over i 4 pick + c@ <> - i 8 mod 1 = if emit 0 then loop ;

在线尝试!

输入是标准的Forth字符串(地址和长度),输出打印到stdout

说明

over c@          \ get the value of the first character in the string
0 rot            \ add a starting "byte" value of 0 and put the length on top of the stack
2 do             \ start a loop from 2 to length-1
   2*            \ multiply the current byte value by 2 (shift "bits" left one)
   over          \ copy the reference char to the top of the stack
   i 4 pick +    \ add the index and the starting address to get address of the current char
   c@ <>         \ get the char at the address and check if not equal to the reference char
   -             \ subtract the value from our bit count, -1 is default "true" value in forth
   i 8 mod 1 =   \ check if we are at the last bit in a byte
   if            \ if we are
      emit 0     \ print the character and start our new byte at 0
   then          \ and end the if statement
loop             \ end the loop
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.