쿼터니언 파싱


27

아직 모른다면 쿼터니언은 기본적으로 4 파트 숫자입니다. 이 도전의 목적을 위해, 그것은 실제 성분과 3 개의 가상 성분을 가지고 있습니다. 상상의 구성 요소는 접미사로 표현된다 i, j, k. 예를 들어, 1-2i+3j-4k함께 쿼터니언이다 1실수 성분과 인 -2, 3-4허수 성분 인.

이 도전에서는 쿼터니언 (예 :)의 문자열 형식 "1+2i-3j-4k"을 계수 목록 (예 :)으로 구문 분석해야합니다 [1 2 -3 -4]. 그러나 쿼터니언 문자열은 다양한 방식으로 형식화 될 수 있습니다.

  • 정상일 수 있습니다. 1+2i-3j-4k
  • 용어가 누락되었을 수 있습니다. 1-3k, 2i-4k( 용어가 누락 된 경우 0해당 용어에 대한 출력 )
  • 이 계수 누락 가질 수있다 i+j-k(이 경우,이 동등 1i+1j-1k즉,. i, j또는 k앞의 번호가있는 것으로 가정하지 않고 1기본적으로 앞)
  • 올바른 순서가 아닐 수 있습니다. 2i-1+3k-4j
  • 계수는 단순히 정수 또는 소수 일 수 있습니다. 7-2.4i+3.75j-4.0k

파싱하는 동안주의해야 할 사항이 있습니다.

  • 항상 +또는 -용어 사이에 있습니다
  • 항상 최소 1 개의 용어를 사용하고 반복되는 문자 ( j-js) 없이 유효한 입력이 전달됩니다.
  • 모든 숫자는 유효하다고 가정 할 수 있습니다
  • 당신은 당신이 원하는 경우 구문 분석 후 다른 형태로 번호를 변경할 수 있습니다 (예. 3.0 => 3, 0.4 => .4, 7 => 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

@FryAmTheEggman No. 입력은 결코로 시작하지 않습니다 +.
GamrCorps 2016 년

1
-0마지막 두 예제에 대한 법적 출력의 일부?
isaacg 2016 년

1
@isaacg 예, 괜찮습니다
GamrCorps 2016 년

1
@LLlAMnYP 좋은 지적입니다. eval문자열에서 제한을 정의하고 코드 및 / 또는 입력으로 해석합니다. 예를 들어, "test"정수를 받기 위해 정수 변환 함수로 문자열 을 전달할 수 없지만 test일반 eval함수 에서는 코드로 해석 되기 때문에 모든 변환은이 계산에 포함되지 않습니다 . TLDR : 평가 : 아니오, 유형 변환 : 예.
GamrCorps

답변:


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 바이트가 절약되었습니다 .

@Martin Büttner 덕분에 버그 수정 및 6 바이트 절약

일부 경우와 관련된 몇 가지 버그가 발견되어 바이트 수가 상당히 늘어났습니다.

줄 바꿈으로 구분 된 숫자를 반환합니다. 어쨌든, 이것은 대부분의 경우에 우연한 사례로 인해 망가지는 우아한 솔루션이지만 정렬 모드를 사용해야합니다. 즉, 작업에 적합한 도구를 사용 했습니까?

설명:

평소와 같이 단계별로.

\b[ijk]
1$&

입력에서 단어 경계를 만들 수있는 유일한 문자는 -+.입니다. 이것은 글자 다음에 경계가 있으면 암시 적 1으로 대체 문자 를 추가 한다는 의미입니다 . $&의 동의어입니다 $0.

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

Martin에게 큰 감사의 말을 들었습니다 0. 입력에서 누락 된 경우 실제 부분에 암시 적으로 추가됩니다 . 더하기 또는 빼기 부호 또는 문자열 끝이 뒤에 오는 숫자를 찾을 수 없도록합니다. 모든 복소수 뒤에 문자가 표시됩니다.

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

다음 3 단계는 모두 거의 동일하며 영향을 미치는 문자를 제외합니다. 그들 모두는 우리가 글자와 일치하지 않는지, 그리고 0용어를 추가 할 수 없는지 확인 합니다. 유일한 이유 i는 s 계수 +로 실제 값을 읽을 수 없도록하기 위한 추가 사항 이 i있으며 다른 숫자는 모두 복잡한 변수로 구분됩니다.

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

아, 재밌는 부분. O옵션 구분 기호 backtick 앞에 표시되는 새로운 정렬 단계를 사용합니다 . 여기서의 요령은 정수와 단어 문자를 선택적으로 붙잡는 것입니다 ijk. 이 경우에는 오직 하나만 일치 합니다. 사용되는 다른 옵션은 $이러한 일치 항목을 정렬하는 데 사용되는 값이 대체 항목이되도록하는 것입니다. 여기서 우리는 정렬 값으로 남은 선택적 문자를 사용합니다. Retina는 기본적으로 사전 식으로 정렬하기 때문에 사전에있는 것처럼 값이 정렬되므로 일치하는 "", "i", "j", "k"순서대로 정렬됩니다.

-
+-

이 단계 +는 모든 빼기 부호 앞에 부호를 표시 i합니다. 나중에 분리 단계에서 음수 값을 갖는 경우 필요합니다 .

^ \ +

+추가 행간이 없어 지도록 행간 을 제거합니다 .

S`[ijk+]+

복합 변수 또는 더하기 부호의 런에서 나머지 행을 분할합니다. 이것은 라인 당 하나의 값을 제공합니다.


3

펄 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 슬프게도, 제안 된 변경 사항 이 예상 한대로 수행되지 않습니다. 답변을 게시하기 전에 시도했습니다. ;-)
Chris Jester-Young

@KennyLau 이 제안 된 변경 과 관련하여 Perl은 \a알파벳이 아니라 "알람"에 일치합니다. 거기에 \w단어 문자 (영숫자와 밑줄)을 위해,하지만 여기에 작동하지 않습니다; 우리는 숫자와 일치하지 않아도됩니다.
Chris Jester-Young

3
@KennyLau BTW, 당신은 채팅 에서 이야기하기에 충분한 담당자가 있습니다. 수정 제안을 계속 거부하지 않고 아이디어를 자유롭게 논의하십시오. ;-)
Chris Jester-Young

나는 또한 의견을 말할 충분한 담당자가 있습니다. Perl은 [az] 패턴이 없습니까?
Leaky Nun

1
@KennyLau 내 지식이 아닙니다.
Chris Jester-Young

3

루아 , 185 (187) 195 (183) 166 바이트 ( 온라인 체험 ) 사용할 정규식]

개선 된 정규식에 대한 @Chris Jester-Young 에게 감사합니다 .

166 바이트 로 줄인 @Katenkyo 에게 감사 합니다.

골프 :

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

대신에, 인수 STDIN에서 입력을 변경하여 일부 바이트를 저장할 수 있어야 io.read()사용 (...). 첫 번째 명령 줄 인수를 가리키고 4 바이트를 더 절약 할 수 있습니다. :
Katenkyo

1
또한 요청 된 출력은 사람이 목록으로 해석 할 수있는 한 아무 것도 될 수 있으므로 추가 서식을 제거 할 수 있습니다. 면도 할 수있는 공백을 더 포함하면 코드가 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," "))
듭니다

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 지금이 OK 인 것이 분명했다.)


3

자바 스크립트 (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

편집 :에서 parseInt로 전환하여 3 바이트를 절약 했습니다 charCodeAt. 이것은 편리한 &3배열 인덱스를 가져 오기 만하면됩니다 .


좋은 생각 파싱 + 모드. 기본 및 접두사에 대한 생각
edc65

1

자바 스크립트 (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. 모든 + 또는-부호 NOT 뒤에 숫자가 있으면 각각 "+1"/ "-1"로 바뀝니다.

  2. lambda함수 sorted에서 키로 사용될 때 전체 숫자를 먼저 넣고 나머지 문자를 증가하는 문자 값 ( "i", "j", "k")으로 정렬 하는 함수가 정의 됩니다. 이 경우).

  3. 이제 필요한 경우 정규식을 사용하여 모든 +/- 부호가 1로 바뀌는 쿼터니언에서 하나 이상의 숫자가 앞에 오지 않는 모든 문자를 검색하고 일치하는 문자는 "+1"로 대체됩니다. 그 편지.

  4. 그런 다음 "if"문은 ALL +/- 부호를 공백으로 바꾼 다음 수정 된 Quaternion이 해당 공백에서 "분할"되어 목록으로 반환됩니다. 그런 다음 목록은 앞에서 설명한 람다 함수에 따라 정렬됩니다. 마지막으로, 해당 목록의 첫 번째 항목은 숫자인지 확인하기 위해 검사되며, 숫자가 아닌 경우 "+0"이 Quaternion에 추가됩니다.

  5. 두 번째 "for"루프는 표현식에서 찾은 문자 세트와 필요한 모든 문자를 포함하는 세트 사이에서 대칭적인 차이를 찾아 Quaternion에없는 모든 문자를 찾습니다. 발견되면 "+0"다음에 누락 된 문자와 공백이 쿼터니언에 추가됩니다.

  6. 마지막으로,이 마지막 단계에서 ","가 각 문자 사이 에 +/- 기호 로 추가 다음 쿼터니언이 해당 공간에서 분할 된 다음 반환 된 목록이 마지막으로 정렬됩니다. 앞서 "q"로 정의 된 람다 함수. 식의 쉼표 (, 그렇지 않으면, 당신은 같은 것을 받고있을 것이다 사원 수의 각 부분 분리 14i+5j+6k에서을 4i+5j+6k+1). 마지막으로, 정렬 된 목록은 문자열로 결합되며 모든 유형숫자 (정규 표현식 제공) 만 추출되고 마지막으로 매번 올바른 순서로 목록으로 반환됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.