クォータニオンの解析


27

まだ知らない場合、クォータニオンは基本的に4部構成の数字です。この課題のために、コンポーネントと3つのコンポーネントがあります。虚数成分は、接尾辞ijで表されkます。例えば、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

解析中に注意すべきことがいくつかあります。

  • 常に用語+または-用語の間にあります
  • 少なくとも1つの用語を含む有効な入力が常に渡され、文字は繰り返されません(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

@FryAmTheEggmanいいえ。入力はで始まることはありません+
GamrCorps

1
ある-0最後の2つの例のための法的出力の一部?
isaacg

1
@isaacgはい、大丈夫です
-GamrCorps

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最後の2つのケースで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+

次の3つのステージは、どの文字が影響するかを除いて、すべてほぼ同じです。それらのすべては、文字に一致しないかどうか、および0それに対する用語を追加できないかどうかを確認します。唯一の理由i+、実際の値がis係数で判読不能になるのを防ぐためです。他の数値はすべて複素変数で区切られています。

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

ああ、楽しい部分です。これは、Oオプションセパレータバックティックの前に示されている、新しいソートステージを使用します。ここでの秘Theは、整数とそれに続くオプションの単語文字を取得することですijk。この場合、これはの1つにのみ一致します。使用される他のオプションは$、これらの一致をソートするために使用される値を置換するものです。ここでは、ソート値として残ったオプションの文字を使用します。Retinaはデフォルトで辞書式にソートされるため、値は辞書にあるようにソートされます"", "i", "j", "k"。つまり、一致するものが順番に取得されます。

-
+-

この段階では、+すべてのマイナス記号の前に記号を配置します。これはi、後で分割段階で負の値を設定する場合に必要です。

^ \ +

先行を削除し+て、余分な先行改行がないようにします。

S`[ijk+]+

複素変数またはプラス記号の実行時に残りの行を分割します。これにより、行ごとに1つの値が適切に提供されます。


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はアルファベットではなく「アラーム」に一致します。あります\w単語文字(英数字とアンダースコア)のために、それはここでは動作しません。数字と一致しないようにする必要があります。
クリスジェスターヤング

3
@KennyLauところで、チャットで話すのに十分な担当者がいます。編集の提案を絶えず拒否するのではなく、そこで自由にアイデアについて話し合ってください。;-)
クリスジェスターヤング

また、コメントするのに十分な担当者がいます。Perlには[az]のパターンはありませんか?
リーキー修道女

1
@KennyLau知らない。
クリスジェスターヤング

3

Lua185 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

あなたは、引数に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," "))
Katenkyo

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

編集:からparseIntに切り替えて3バイトを節約しましたcharCodeAt。これ&3は、正しい配列インデックスを取得するだけで便利です。


素晴らしいアイデアparseInt + mod。ベースとプレフィックスについて考える
-edc65

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つの数字が前にないすべての文字を検索し、一致する文字は「+1」に続いてその手紙。

  4. 「if」ステートメントは、すべての+/-記号をスペースに置き換え、変更されたクォータニオンはそれらのスペースで「分割」され、リストに返されます。次に、リストは前述のラムダ関数に従ってソートされます。最後に、リスト内の最初のアイテムがチェックされ、数字であることが想定されます。数字でない場合は、「+ 0」がクォータニオンに追加されます。

  5. 2番目の「for」ループは、式で見つかった文字のセットと、必要なすべての文字を含むセットの対称差を見つけることにより、クォータニオンにないすべての文字を見つけます。見つかった場合、「+ 0」の後に欠落文字とスペースが続き、クォータニオンに追加されます。

  6. 最後に、この最後のステップで、各文字の間に「、」が追加さ、その後に+/-記号が追加されます。その後、クォータニオンがそれらのスペースで分割され、返されるリストが最後にソートされます以前に「q」として定義されたラムダ関数。式のコンマは、クォータニオンの各部分を区切ります(そうでない場合は、14i+5j+6kからのようなものになります4i+5j+6k+1)。最後に、ソートされたリストは文字列に結合され、すべてのタイプ番号 (正規表現のおかげ)のみが抽出され、最終的に正しい順序で毎回リストに返されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.