解析四元数


27

如果您还不知道,则四元数基本上是4位数的数字。出于这一挑战的目的,它具有一个实部和三个虚部。虚数分量是由后缀表示ijk。例如,1-2i+3j-4k是用四元数1为实分量和-23-4作为虚数分量。

在此挑战中,您必须将四元数的字符串形式(例如"1+2i-3j-4k")解析为系数(例如[1 2 -3 -4])的列表/数组。但是,四元数字符串可以用多种不同的格式进行格式化...

  • 这可能是正常的: 1+2i-3j-4k
  • 它可能缺少术语:1-3k2i-4k(如果缺少术语,则输出0这些术语)
  • 它可能已丢失的系数:i+j-k(在此情况下,这相当于1i+1j-1k换句话说,一个。ij,或k不被假定在前面的数以具有1在由缺省前)
  • 它的顺序可能不正确: 2i-1+3k-4j
  • 系数可以只是整数或小数: 7-2.4i+3.75j-4.0k

解析时有一些注意事项:

  • 条款之间总会有a +-
  • 您将始终获得有效的输入信息,该输入内容至少包含1个字词,并且没有重复的字母(no j-js)
  • 所有数字都可以视为有效
  • 你可以,如果你想解析后更改号码为另一种形式(例如,3.0 => 30.4 => .47 => 7.0

不允许使用解析/四元数内置函数和标准漏洞。这包括eval关键字和功能。输入将是单个字符串,输出将是列表,数组,由空格分隔的值等。

因为这是,所以以字节为单位的最短代码获胜。

吨测试用例

1+2i+3j+4k             => [1 2 3 4]
-1+3i-3j+7k            => [-1 3 -3 7]
-1-4i-9j-2k            => [-1 -4 -9 -2]
17-16i-15j-14k         => [17 -16 -15 -14]

7+2i                   => [7 2 0 0]
2i-6k                  => [0 2 0 -6]
1-5j+2k                => [1 0 -5 2]
3+4i-9k                => [3 4 0 -9]

42i+j-k                => [0 42 1 -1]
6-2i+j-3k              => [6 -2 1 -3]
1+i+j+k                => [1 1 1 1]
-1-i-j-k               => [-1 -1 -1 -1]

16k-20j+2i-7           => [-7 2 -20 16]
i+4k-3j+2              => [2 1 -3 4]
5k-2i+9+3j             => [9 -2 3 5]
5k-2j+3                => [3 0 -2 5]

1.75-1.75i-1.75j-1.75k => [1.75 -1.75 -1.75 -1.75]
2.0j-3k+0.47i-13       => [-13 0.47 2.0 -3] or [-13 .47 2 -3]
5.6-3i                 => [5.6 -3 0 0]
k-7.6i                 => [0 -7.6 0 1]

0                      => [0 0 0 0]
0j+0k                  => [0 0 0 0]
-0j                    => [0 0 0 0] or [0 0 -0 0]
1-0k                   => [1 0 0 0] or [1 0 0 -0]

+输入中是否会有不必要的信号?喜欢:+1k
FryAmTheEggman '16

@FryAmTheEggman编号输入永远不会以开头+
GamrCorps

1
-0最后两个例子合法的输出的一部分吗?
isaacg

1
@isaacg是的,这很好
GamrCorps

1
@LLlAMnYP您提出了一个很好的观点。让我们定义eval限制在字符串中,解释为代码和/或输入。在这种情况下,任何转换都不算在内,因为您不能将例如字符串"test"传递给整数转换函数以接收整数,但是test在正常eval函数中它将被解释为代码。TLDR:eval:否,类型转换:是。
GamrCorps '16

Answers:


5

Pyth,48个字节

jm+Wg\-K--e|d0G\+K1+]-I#GJczfT.e*k<b\.zm/#dJ"ijk

演示 测试套件

输出格式以换行符分隔。测试套件代码使用空格分隔,以便于阅读,但其他方面是相同的。

-0在最后两种情况下输出a ,我希望可以。

解释如下。


9

视网膜115

\b[ijk]
1$&
^(?!.*\d([+-]|$))
0+
^(?!.*i)
+0i+
^(?!.*j)
0j+
^(?!.*k)
0k+
O$`[+-]*[\d.]*(\w?)
$1
-
+-
^\+

S`[ijk+]+

在线尝试!

感谢@Chris Jester-Young节省了1个字节。

@MartinBüttner修复了一个错误,并节省了6个字节

发现了一些涉及某些极端情况的错误,字节计数增加了很多。

返回换行符分隔的数字。无论如何,这是一个非常优雅的解决方案,它会被边缘情况破坏,但是嘿,我必须使用排序模式,这意味着我使用了正确的工具进行工作,对吗?

说明:

与往常一样,逐步进行。

\b[ijk]
1$&

输入中唯一可以创建单词边界的字符是-+.。这意味着,如果找到边界后跟一个字母,则会有一个隐式变量1,并在其中添加替换内容。$&是的同义词$0

^(?!.*\d([+-]|$))
0+

非常感谢Martin撰写的这篇文章,0如果输入中缺少该部分,则为其中的隐含部分进行补充。我们确保找不到以加号或减号或字符串结尾的数字。所有复数之后都会有一个字母。

^(?!.*i)
+0i+

接下来的三个阶段几乎相同,除非它们影响哪个字母。他们所有人都在看我们是否无法匹配字母,如果不能匹配,我们会0为其添加一个术语。唯一的原因,i有一个额外的+之前,它是为了防止读取与真实值i系数的分析,其他数字都是通过分离其复杂的变量。

O$`[+-]*[\d.]*(\w?)
$1

啊,有趣的部分。这使用新的排序阶段,由O选项分隔符反引号之前的表示。这里的技巧是获取整数,然后可选地带一个单词字符,在这种情况下,该字符只会匹配之一ijk。使用的另一个选项是$使用于对这些匹配项进行排序的值替换。在这里,我们只使用剩余的可选字母作为排序值。由于Retina默认情况下按字典顺序排序,因此对值的排序就像在字典中一样,这意味着我们将按顺序获取匹配项"", "i", "j", "k"

-
+-

此阶段+在所有减号之前放置一个符号,如果i稍后在split阶段中该值的值为负,则需要这样做。

^ \ +

我们删除潜在客户+,以确保没有多余的潜在客户换行符。

S`[ijk+]+

在复杂变量或加号的运行上拆分其余行。这很好地为我们提供了每行一个值。


3

Perl 5,125个字节

#!perl -p
%n=(h,0,i,0,j,0,k,0);$n{$4//h}=0+"$1@{[$3//$5//1]}"while/([+-]?)(([\d.]+)?([ijk])|([\d.]+))/g;s/.*/@n{qw(h i j k)}/

1
@KennyLau不幸的是,您提出的更改没有达到您的期望。在发布答案之前,我已经尝试过了。;-)
克里斯·杰斯特·杨

@KennyLau关于此提议的更改,Perl的\a匹配为“ alarm”,而不是字母顺序。这里有\w单词字符(字母数字和下划线),但是在这里不起作用。我们需要它与数字不匹配。
克里斯·杰斯特·杨

3
@KennyLau顺便说一句,您有足够的代表可以聊天。随时在此处讨论想法,而不是不断拒绝您的编辑建议。;-)
克里斯·杰斯特·杨

我现在也有足够的代表发表评论。Perl没有[az]的模式吗?
Leaky Nun

1
@KennyLau据我所知。
克里斯·杰斯特·杨

3

Lua中185个 187 195 183 166字节(在线试用)使用正则表达式]

感谢@Chris Jester-Young改进了正则表达式。

感谢@Katenkyo将其压缩到166个字节。

打高尔夫球:

r={0,0,0,0}for u in(...):gsub("([+-])(%a)","%11%2"):gmatch("-?[%d.]+%a?")do n,i=u:match("(.+)(%a)")r[i and(" ijk"):find(i)or 1]=(n or u)end print(table.concat(r," "))

取消高尔夫:

n = "42i+j-k+0.7"

result = {0,0,0,0}

for unit in n:gsub("([+-])(%a)","%11%2"):gmatch("-?[%d.]+%a?") do
  num, index = unit:match("(.+)(%a)")
  if index == "i" then
    result[2] = num
  elseif index == "j" then
    result[3] = num
  elseif index == "k" then
    result[4] = num
  else
    result[1] = unit
  end
end

print(table.concat(result," "))

2
嗨,肯尼,感谢您的解决方案。通常,我们不允许输入以变量开头(n在这种情况下),因此您应该添加代码以读取输入。
isaacg '16

通过将输入从STDIN更改为参数,而不是io.read()use ,您应该能够节省一些字节(...)。它将指向第一个命令行参数,并允许您再保存4个字节:)
Katenkyo

1
另外,要求的输出可以是任何东西,只要人类可以将其解释为列表即可,因此您可以删除多余的格式。包括一些可以r={0,0,0,0}for u in(...):gsub("([+-])(%a)","%11%2"):gmatch("-?[%d.]+%a?")do n,i=u:match("(.+)(%a)")r[i and(" ijk"):find(i)or 1]=(n or u)end print(table.concat(r," "))
删除的

3

C,236字节

char j,n[9][9],s[9],y[9],i=8,k,*p=n[8];main(c){for(**n=48;c=getchar(),c+1;)c-32&&(c<46&&(k&&(y[1]=i),k=0,s[--i]=c-43,p=n[i])||c>57&&(k||(*p=49),k=0,y[c-103]=i)||(*p++=c,k=1));for(k&&(y[1]=i);++j<5;)printf("%c%s ",s[y[j]]?45:0,n[y[j]]);}

(对于-0或-0.0之类的值,也会在输出中打印减号,但是由于质询指出“如果需要,您可以在解析后将数字更改为另一种形式”,并且-0出现在输入中,因此,它在输出中也是可以接受的。 @ GamrCorps现在澄清了这是可以的。)


3

的JavaScript(ES6),103个 100字节

f=s=>s.replace(/(?=.)(\+|-|)([\d.]*)(\w?)/g,(_,s,x,c)=>a[c.charCodeAt()&3]=+(s+(x||1)),a=[0,0,0,0])&&a

编辑:通过从切换parseIntcharCodeAt,节省了3个字节,只需方便&3地获取正确的数组索引即可。


好主意parseInt + mod。关于基址和前缀的思考
edc65 '16

1

JavaScript(ES6)106

s=>(s.replace(/([+-]?)([\d.]*)(\w?)/g,(a,b,c,d)=>a&&(s[d||9]=b+(c||1)),s={}),[...'9ijk'].map(i=>+s[i]||0))

测试

f=s=>(s.replace(/([+-]?)([\d.]*)(\w?)/g,(a,b,c,d)=>a&&(s[d||9]=b+(c||1)),s={}),[...'9ijk'].map(i=>+s[i]||0))

function Test()
{
  var t,k,r,ts=TS.value.split('\n')
  
  O.textContent=ts.map(x=>x.trim()&&(
    [t,k]=x.split('=>').map(x=>x.trim()),
    console.log(t,'*',k),
    k=k.match(/[\d+-.]+/g).map(x=>+x),
    r=f(t),
    t+' => '+r+(r+''==k+''?' OK':' KO (check: '+k+')')
  )).join('\n')
}    

Test()
#TS { width:90%; height:10em}
<pre id=O></pre>

Test data (modify if you like)<button onclick='Test()'>repeat test</button>
<textarea id=TS>
1+2i+3j+4k             => [1 2 3 4]
-1+3i-3j+7k            => [-1 3 -3 7]
-1-4i-9j-2k            => [-1 -4 -9 -2]
17-16i-15j-14k         => [17 -16 -15 -14]
  
7+2i                   => [7 2 0 0]
2i-6k                  => [0 2 0 -6]
1-5j+2k                => [1 0 -5 2]
3+4i-9k                => [3 4 0 -9]
  
42i+j-k                => [0 42 1 -1]
6-2i+j-3k              => [6 -2 1 -3]
1+i+j+k                => [1 1 1 1]
-1-i-j-k               => [-1 -1 -1 -1]
  
16k-20j+2i-7           => [-7 2 -20 16]
i+4k-3j+2              => [2 1 -3 4]
5k-2i+9+3j             => [9 -2 3 5]
5k-2j+3                => [3 0 -2 5]
  
1.75-1.75i-1.75j-1.75k => [1.75 -1.75 -1.75 -1.75]
2.0j-3k+0.47i-13       => [-13 0.47 2.0 -3]
5.6-3i                 => [5.6 -3 0 0]
k-7.6i                 => [0 -7.6 0 1]
  
0                      => [0 0 0 0]
0j+0k                  => [0 0 0 0]
-0j                    => [0 0 0 0]
1-0k                   => [1 0 0 0]
</textarea>


0

PowerShell,178个字节

param($a);$p="(-?)([\d.]+)?";$g={param($s)if($a-match"$p$s"){if(($r=$matches)[2]){$r[1]+$r[2]}else{$r[1]+1}}else{0}};$a-match"$p(\+|-|$)">$null;+$matches[2];"i","j","k"|%{&$g $_}

脱离解释

# Get the whole string into a variable
param($a)
# Pattern shared getting both imaginary and real numbers. 
$p="(-?)([\d.]+)?"
# Anonymous function that will locate a imaginary number using a letter sent as a parameter. 
# If no value is assigned a signed 1 is returned. If no value is matched 0 is returned
$g={param($s)if($a-match"$p$s"){if(($r=$matches)[2]){$r[1]+$r[2]}else{$r[1]+1}}else{0}}
# Locate the real component if any. Null is converted to 0
$a-match"$p(\+|-|$)">$null;+$matches[2]
# Call the anonymous function using each of the imaginary suffixes.                                               
"i","j","k"|%{&$g $_}

并没有给人留下深刻的印象,但这仍然是结果。


0

PHP,179字节

$a=[''=>0,'i'=> 0,'j'=>0,'k'=>0];preg_match_all("/([-+]?)(\d*(\.\d+)?)([ijk]?)/",$argv[1],$m,2);foreach($m as$n)if($n[0])$a[$n[4]]=$n[1].($n[2]===''?1:$n[2]);echo implode(',',$a);

尝试测试套件


0

Python 3.5-496个字节[使用正则表达式]:

from re import*
def wq(r):
 a=sub('[+](?![0-9])','+1',sub('[-](?![0-9])','-1',r));q=lambda x:(not x.isdigit(),''.join(filter(str.isalpha,x)))
 for z in findall('(?<![0-9])[a-z]',a):a=a.replace(z,('+1{}'.format(z)))
 if not str(sorted(((sub('[.]','',sub('[+-]',' ',a))).split(' ')),key=q)[0]).isdigit():a+='+0, '
 for i in list(set(findall('[a-z]',a))^{'i','j','k'}):a+='+0{}, '.format(i)
 print(findall('[-]?\d+(?:\.\d+)?',''.join(sorted(sub('(?<=[A-Za-z0-9])(?=[+-])',', ',a).split(' '),key=q))))

可能会很长,但是出于我的辩护,它可以完美地完成OP所需的工作,因为给出的所有测试用例都可以成功使用我的代码。

非高尔夫版本,并附有说明:

from re import*
def w(r):
    # Substitute all minus (-) and plus (+) signs NOT followed by a number  (if there are any) with a "-1"/"+1", respectively.
    a=sub('[+](?![0-9])','+1',sub('[-](?![0-9])','-1',r))
    # Lambda function created for later use to sort the Quaternion. This function, when given as a key to the "sorted" function, arranges the input Quaternion in the order where the whole number comes first, and then the rest are placed in order of increasing letter value (i,j,k in this case) 
    q=lambda x:(not x.isdigit(),''.join(filter(str.isalpha,x)))
    # The following "for" loop replaces the letters NOT preceded by a number with a one followed by that letter
    for z in findall('(?<![0-9])[a-z]',a):
        a=a.replace(z,('+1{}'.format(z)))
    # The following first substitutes all pluses and minuses (+ and -) with a space, and then that new string is split at those spaces, and returned as a list. After that, the list is sorted according the the "lambda" function shown above. Then, the first item in that list, which is supposed to be a lone number, is checked to make sure that it indeed is a lone number. If it isn't, then "+0, " is appended to the Quaternion. 
    if not str(sorted(((sub('[.]','',sub('[+-]',' ',a))).split(' ')),key=q)[0]).isdigit():
        a+='+0, '
    # The following "for" loop finds ALL the letters NOT in the list, by finding the symmetric difference between a set of all the letters found, and a set containing all the letters needed. For the letters not in the list, a '+0' is added the quaternion, followed by that letter, and then a comma and a space.
    for i in list(set(findall('[a-z]',a))^{'i','j','k'}):
        a+='+0{}, '.format(i)
    # Finally, in this last step, a ", " is added IN BETWEEN unicode characters and pluses/minuses (+/-). Then, it splits at those spaces, and the commas separate different parts of the Quaternion from each other (otherwise, you would get something like `12i+3j+4k` from `2i+3j+4k+1`) in a returned list. Then, that list is sorted according to the lambda expression "q" (above), and then, finally, the NUMBERS (of any type, courtesy to Regex) are extracted from that joined list, and printed out in the correct order.
    print(findall('[-]?\d+(?:\.\d+)?',''.join(sorted(sub('(?<=[A-Za-z0-9])(?=[+-])',', ',a).split(' '),key=q))))

如果上面的内容有点难以理解,那么基本上是这样的:

  1. 如果有的话,所有不带数字的+或-号分别用“ +1” /“-1”代替。

  2. lambda函数被定义,其中在使用时,sorted可作为一键,根据使整个数量的第一,然后订购其余增加字母值(排序列表中的“I”,然后是“J”,则“K”在这种情况下)。

  3. 现在,使用正则表达式搜索四元数(如果需要,将所有+/-符号替换为1),查找所有不带至少一个数字的字母,然后将匹配的那些字母替换为“ +1”那封信。

  4. 然后,“ if”语句用空格替换所有+/-符号,然后将修改后的四元数“拆分”在这些空格处,并以列表形式返回。然后,根据前面解释的lambda函数对列表进行排序。最后,检查该列表中的第一项以确保它是一个数字(因为应该是数字),如果不是,则将“ +0”添加到四元数。

  5. 第二个“ for”循环通过查找表达式中找到的一组字母与包含所有所需字母的一组字母之间的对称差,找到四元数中所有不在NOT中的字母。如果找到任何一个,则在四元数中添加“ +0”,后跟丢失的字母和空格。

  6. 最后,在最后一步中,每个字符之间添加一个“,” 后跟一个+/-符号,然后在这些空格处拆分四元数,最后一次对返回的列表进行排序,具体取决于之前定义为“ q”的lambda函数。表达式中的逗号分隔的四元数的每个部分(否则,你会得到类似14i+5j+6k4i+5j+6k+1)。最后,将现在已排序的列表连接在一起成为一个字符串,并且每次仅提取任何类型数字 (由正则表达式提供),并最终以正确的顺序返回到列表中。

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.