電子書籍の厳選無料作品が豊富!

perlでプログラムを作成中です。
作成したモノはうまく動かないので掲載できませんが、
どなたかお知恵を貸してください。

 入力文字列に対して
1をA、2をB、3をC
に置換するプログラムを作成中です。
ただし、全ての組み合わせを出力したいのです。
つまり、”213”と入力すると回答は、
B13
BA3
BAC
2A3
21C
2AC
B1C

と出力したいのです。
 プログラムとしては、入力文字列を1つずつを配列に入れて、それぞれの変換
をかけ、1つずつ組み合わせて出力しているのですが、どうもうまくいきません。
手法は特に固執してませんので、どの様な形でも結構です。
よろしくお願いします。

A 回答 (16件中1~10件)

#13です。


>あと、変換前にカンマの使用があります。
変換前の文字列にカンマがあるということなので、
変換するファイルをタブ形式で定義したバージョンのスクリプトを
参考URLに書きました。(バージョン3 (CL.3)になります。)(カンマをタブに替えただけす。)

ファイルの1行は
変換前文字列<tab>変換後文字列1<tab>変換後文字列2<tab>・・・変換後文字列N
の形式で定義してください。
<tab>はタブ文字"\t"を意味します。

変換前文字列、変換後文字列の何れも カンマ(",")を変換文字として使用可能です。

,1<tab>A<tab>B

",1"をAに変換し、かつ
",1"をBに変換します。


>ちなみに前文はケース2の場合を想定してました。
定義の方法はケース1で行っていますが、
どうしても定義2でなければいけない理由があるのでしょうか?
もし、そうであれば、その旨補足ください。
スクリプトをケース2の形式に対応させるのは、簡単にできます。

参考URL:http://climbi.com/b/3383/3
    • good
    • 0
この回答へのお礼

 出来ました!理想とするプログラムができあがって理解することも出来ました。
長々とお付き合いありがとうございました。
ケース2にしたかった理由は、変換される文字より変換後の文字の方が少なかったので、
テキストファイルが見やすくなると思ったのです。
ですが、作ってみると、ケース1の方が便利な理由が出来たので、このまま行きます。
本当にありがとうございました。
他の方も回答してくださっているようなので、そちらの方も勉強してみようと思います!

お礼日時:2015/01/14 23:08

次のプログラムで。

一応はすべての組み合わせを生成できると思います。

use strict;
use warnings;
my %convert = qw(1 A 2 B 3 C 4 D 5 E 6 F 7 G 8 H 9 I);

while (<DATA>) {
print; chomp;
my @line = grep { length } split /(\d)/;
my @idx = (0) x @line;
my @num_idx = grep { $line[$_] =~ /[1-9]/ } 0 .. $#line;
my @incr = (0) x @num_idx;
for (my $i = $#incr; $i >= 0 ;$i--) {
if ($incr[$i]) {
$incr[$i] = 0;
$idx[$num_idx[$i]] = 0;
} else {
$incr[$i]++;
$idx[$num_idx[$i]] = 1;
print join('', map { $idx[$_] ? $convert{$line[$_]} : $line[$_] } 0 .. $#idx), "\n";
$i = $#incr; redo;
}
}
}

__DATA__
213
--4-153--62-
    • good
    • 0

うん, なんかできたっぽい.



#!/usr/bin/perl

use strict;
use 5.016;
use feature 'say';

sub readConversion {
my ($fh) = @_;
my %conversion_pairs;
while (<$fh>) {
chomp;
my ($pattern, @replace) = split /,/;
$conversion_pairs{$pattern} = \@replace;
}
%conversion_pairs;
}

sub convert_ {
my ($pairs, $patterns, $conversions, $active_patterns, @sources) = @_;
my ($pattern_head, @pattern_rest) = @$patterns;
my %conversions = %$conversions;
my @active_patterns = @$active_patterns;

my @result;

if (defined $pattern_head) {
@result = convert_($pairs, \@pattern_rest, \%conversions, \@active_patterns, @sources);
push @active_patterns, $pattern_head;
for my $pattern (@{$pairs->{$pattern_head}}) {
$conversions{$pattern_head} = $pattern;
push @result, convert_($pairs, \@pattern_rest, \%conversions, \@active_patterns, @sources);
}
} else {
if (@active_patterns) {
my $pattern = join '|', map { quotemeta } @active_patterns;
@result = map { s/($pattern)/$conversions{$1}/gr; } @sources;
} else {
@result = @sources;
}
}

@result;
}

sub convert {
my ($pairs, @sources) = @_;
my @conversion_patterns = sort { length $b <=> length $a } keys %$pairs;

convert_($pairs, \@conversion_patterns, {}, [], @sources);
}

my %conversion_pairs = readConversion *DATA;
chomp (my $line = <>);
my @results = convert(\%conversion_pairs, $line);
for my $result (@results) {
say $result;
}
__DATA__
1,A,Z
2,B
3,C
123,Z
23,D
32,WXY,HIJ
    • good
    • 0

>第二カラムに変換する可能性がある元値の個数を入れてみました。


>これを使って必要回数分ループさせるつもりです。
これは、
A,3,1,13,j3_
の例では
ケース1:
Aから1に変換
Aから13に変換
Aからj3_に変換
の意味でしょうか。
それとも
ケース2:
1をAに変換
13をAに変換
j3_をAに変換の意味でしょうか。(元値の個数の元値の意味はこのようにも解釈できます)

決めの話になりますが、
今回はケース1とします。
そして、個数を示す3は不要とします。
従って
A,1,13,j3_は
Aを1に変換
Aを13に変換
Aをj3_に変換することとします。

もし
1をAに変換
13をAに変換
j3_ををAに変換したければ
1,A
13,A
j3_,A
のように記述してください。
念の為、確認ですが、カンマは変換後の文字列としては使えないこととします。
もし使えるとすると
A,1,2
の意味は
Aを"1,2"に変換するのか
Aを1に変換し、かつ
Aを2に変換するのかが区別できないためです。
(もし、どうしてもカンマを変換後の文字で使いたい場合はその旨補足ください)

つまり、一般的には
変換前文字列,変換後文字列1,変換後文字列2,・・・変換後文字列N のように記述することとします。
(変換後文字列1は必須、変換後文字列2以降は任意です)
>これで同じだと思ったのですが、回答が出ません。
以前、私が書いたスクリプトは、
変換前の文字列は1文字かつ変換後の文字列も1文字という前提です。
つまり1文字を1文字に変換だけしかできません。
最終的には1文字をn文字、n文字を1文字に変換等になりますので、
前回のスクリプトは全く使用できません。全て書き直しになります。

この変換用のファイル(sample.txt)の内容が、
1,A,Z
2,B
3,C
123,Z
23,D
32,WXY,HIJ

の時、スクリプト(sample.pl)を実行した結果は、以下の通りです。
スクリプトの詳細は参考URLを参照ください。

perl sample.pl sample.txt
1->A,Z
2->B
3->C
123->Z
23->D
32->WXY,HIJ
入力してください->1232x
44 通りの組合せがあります
1232x
123Bx
12C2x
12CBx
12HIJx
12WXYx
1B32x
1B3Bx
1BC2x
1BCBx
1BHIJx
1BWXYx
1D2x
1DBx
A232x
A23Bx
A2C2x
A2CBx
A2HIJx
A2WXYx
AB32x
AB3Bx
ABC2x
ABCBx
ABHIJx
ABWXYx
AD2x
ADBx
Z232x
Z23Bx
Z2C2x
Z2CBx
Z2HIJx
Z2WXYx
Z2x
ZB32x
ZB3Bx
ZBC2x
ZBCBx
ZBHIJx
ZBWXYx
ZBx
ZD2x
ZDBx

尚、スクリプトの注意点は以下の通りです。
処理を行うとき、1つのキー(変換前文字列)に複数のデータ(変換後文字列)を対応させる
必要がありますが、これは
%conv{$key} = X
Xの部分に配列が簡単に設定できれば良いのですが、(スクリプトが判りづらくなるため)
Xの部分は、変換後の文字列をカンマで区切って1つの文字列として格納しました。
そして、使うときにばらして使うようにしました。

入力文字列をキーで次々と変換しますが、その状態は以下のように管理します。
その入力文字を処理済み文字列と未処理文字列に分けます。
例えば、入力文字列に"1232x"が与えられた時、
最初は、処理済文字列は空文字、未処理文字列は"1232x" となります。
もし、最初の1文字だけ変換した場合は、1をAに変換、1をZに変換しますので
A23x2と
Z232xのようになります。
A23x2についてはAが処理済文字列、232xが未処理文字列になります。
ここで、処理済文字列と未処理文字列を2つ保持する必要があるのですが、
配列(Aと232x)で持つことも出来ますが、このデータは複数ある為、
配列の配列で管理する必要があります。これを避けるため(1次元の配列にするため)
デリミタで分けて管理します。例えばデリミタを|(パイプ、別名縦棒)とすると
A|232x のように保持します。
(実際には|は入力文字中に存在する可能性があるので、デリミタは文字としては絶対存在しない16進数のFF
を使用しています。入力文字列がバイナリデータの場合はだめですが・・・・)
もし、この内部の状態を途中でプリントしたいなら、デリミタにタブ("\t")を使用することは可能です。
(入力文字列にタブがない前提です)
従って、最初は
|1232x
で、つぎに
A|232x
で、最後が
????x| (????はなんらかの変換された文字)
となるまで、繰り替えします。

不明点は補足ください。

参考URL:http://climbi.com/b/3383/0

この回答への補足

凄いプログラムありがとうございます><
コメントもたくさん入れていただいて、わかりやすくしていただいて助かります。
ちなみに前文はケース2の場合を想定してました。
あと、変換前にカンマの使用があります。
CSVの文字列をタブか何かで区切って・・・と試行中です。
とりあえず、理解しながら進めています。
キモになる
($rest_ctr,@array) = &convert(@array);
辺りが混乱して苦戦中であります・・・・。

補足日時:2015/01/11 23:29
    • good
    • 0

#10です。


>上記のため、3文字の抽出用テキストを作り、改めてsubstrで3文字用、
>それ以外に複数文字用のものを作り、順次読み込むという煩雑な方法しか無いでしょうか?

1文字用と3文字用は1つのファイルにまとめて記述できます。

>この定義で前記の例を元にするなら、書いていただいたプログラムの
>$keyにCを入れ$valに”3”や”123”を入れることが出来るでしょうか?
>$valが固定長でないので、やっぱり複数テキストファイルが必要でしょうか?
このケースは、$keyが3で$valがC、$keyが123で$valがCになります。
1をAに変換、かつ1をXに変換する場合が、$keyが1 $valがAとXになります。
これは、定義可能です。

カンマは変換文字にない(変換文字はA~Z、0~9の36文字のみ)ということですので、
以下のように定義できます。第1カラムが変換前文字列、第二カラム以降が変換後文字列
1,A,Z,D は1からA、1からZ、1からDの変換を行うことを意味します。
123,Aは123からAに変換することを意味します。

念のため確認ですが、
1.変換前の文字列は、1桁から36桁までありえる。
例 1からAに変換、1234567890からXに変換など

2.変換後の文字列も、1桁から36桁までありえる。
(変換前の文字数と変換後の文字数は特に規則はない)
例 1234からZに変換1からABCDに変換、12345からABCDEFGHJI変換など

3.入力文字列(変換対象文字列)は、全て半角1文字である。但し、(A~Z、0~9)以外の文字も
含んでいる。

上記の前提で、間違いないでしょうか?
今までに想定していた前提から、条件がかわりますので、プログラムは複雑になりそうですが、
変換用のファイルは1ファイルのみで可能です。
問題は変換対象の文字列が複数混じることを考慮しなければいけないことです。
例えば変換用ファイルで以下のように指定されたとします。
1,A,Z
2,B
3,C
23,D
123,Y
32,GHIJK (これは32をGHIKの文字に変換することであり、32をG、32をH、32をI、32をKに変換することではない)

入力文字列が
1232xの場合
変換対象となる文字列は
1,2,3,23,123,32
のケースが存在し、それらを全て処理する必要があることです。
その為、プログラムは複雑になります。前提条件に誤りがないか、ご確認ください。

この回答への補足

回答ありがとうございます。小出しで混乱させてしまいご迷惑をおかけします。

>1.変換前の文字列は、1桁から36桁までありえる。
>例 1からAに変換、1234567890からXに変換など
入力する文字列と言うことでしたら、何桁でもあり得ます。
ただし、変換前の文字列(例でいう"1234567890")は最大半角6桁ほどです。

>2.変換後の文字列も、1桁から36桁までありえる。
>(変換前の文字数と変換後の文字数は特に規則はない)
>例 1234からZに変換1からABCDに変換、12345からABCDEFGHJI変換など
特に規制はありません。ただし、前回の説明通り、回答は半角A~Z、0~9に集約されます。

>3.入力文字列(変換対象文字列)は、全て半角1文字である。但し、(A~Z、0~9)以外の文字も含んでいる。
その通りです。色々な記号が含まれます。文字コードは定められていません。

 これより、第一カラムはA~Zと0~9の36文字、大二カラム以降カンマで変換前の文字列を列挙していくというテキストを変換することになるのですね。
自分でもがんばって作ってみますが、是非ご指導よろしくお願いします。

補足日時:2015/01/08 22:21
    • good
    • 0
この回答へのお礼

すいません。更に追加します。
読み込みの部分を作ってみましたが、全然変換してくれません。
代入は出来ているようなのですが・・・
なお、読み込みテキストは以下のようにしてみました。
---------------------
A,3,1,13,j3_
B,4,2,234,1ax,1_1
C,2,3,33
---------------------
第二カラムに変換する可能性がある元値の個数を入れてみました。
これを使って必要回数分ループさせるつもりです。
で、プログラムを以下の通りとしました。(読み込み分のみ)
ーーーーーーーーーーーーーーーーーーーー
while(<FH>){
chomp $_;
@d = split(/,/, $_);   #カンマ区切りで分割
$key = @d[0];
for($h = 0;$h < @d[1];$h++) {
$ma = $h + 2;     #第三カラムからconv箱に入れる
$val = @d[$ma];
$conv{$key} = $val;
}
}
ーーーーーーーーーーーーーーーーーーーー
これで同じだと思ったのですが、回答が出ません。
更なるご指導よろしくお願いします。

お礼日時:2015/01/09 00:26

プログラムを書くのは面倒くさいので方向性だけ:



・%conv = (変換前1 => 変換後1, 変換前2 => 変換後2, ...)
のときに $string の「変換前1」を「変換後1」に, 「変換前2」を「変換後2」に, ... と一度に書き換えるのは簡単
・ということで, 全ての変換の組み合わせを取り出してハッシュを作ればいい
・「全ての組み合わせ」を作る古典的な方法は再帰
・再帰するならもともとの変換ペアは配列になってると簡単そう
で例えば #10 の例に対して
@conv = (
{ '1' => [ 'A', 'a', 'b' ] },
{ '2' => [ 'B' ] },
{ '3' => [ 'C' ] },
{ '%' => [ 'D' ] },
{ '&' => [ 'E' ] },
);
という構造を作って上の方向性を逆にたどればいい.
    • good
    • 0

#9です。


変換する文字列の組合せをファイルで指定するようにしたケースです。
以下の前提で作成しています。
変換前の文字列は、半角1文字である。
変換後の文字列は、半角1文字である。
変換対象の文字列は全て半角である。(漢字の文字はない)
変換前の1文字に、変換後の文字が、複数個割り当てができる。

例として、以下のようなファイルを作成します。(名称はsmaple.txtとします)
-----------------------------------
1A
2B
3C
1a
1b
%D
&E
-----------------------------------
1については
1をA
1をa
1をb
に変換する。
2をB
3をC
%をD
&をE
に変換する。
という意味になります。
(カンマも変換文字になる可能性があるのでCSVファイルにはしていません)

perl スクリプトファイル sample.txt
と入力してください。
スクリプトファイルは、参考URLに書いてあります。(名称はsample.plとします)
(このperlのスクリプトは「現在、この回答はサポートで内容を確認中です」となるのでそれの回避の為)
変換文字列を促す、プロンプトが表示されます。
変換文字列を入力すると、結果が表示されます。
以下、実行結果です。
-----------------------------
perl sample.pl sample.txt
入力してください->123%&x
64 通りの組合せがあります
123%&x
123%Ex
123D&x
123DEx
12C%&x
12C%Ex
12CD&x
12CDEx
1B3%&x
1B3%Ex
1B3D&x
1B3DEx
1BC%&x
1BC%Ex
1BCD&x
1BCDEx
A23%&x
A23%Ex
A23D&x
A23DEx
A2C%&x
A2C%Ex
A2CD&x
A2CDEx
AB3%&x
AB3%Ex
AB3D&x
AB3DEx
ABC%&x
ABC%Ex
ABCD&x
ABCDEx
a23%&x
a23%Ex
a23D&x
a23DEx
a2C%&x
a2C%Ex
a2CD&x
a2CDEx
aB3%&x
aB3%Ex
aB3D&x
aB3DEx
aBC%&x
aBC%Ex
aBCD&x
aBCDEx
b23%&x
b23%Ex
b23D&x
b23DEx
b2C%&x
b2C%Ex
b2CD&x
b2CDEx
bB3%&x
bB3%Ex
bB3D&x
bB3DEx
bBC%&x
bBC%Ex
bBCD&x
bBCDEx

参考URL:http://climbi.com/b/3355/0
    • good
    • 0
この回答へのお礼

こんばんは。
ありがとうございます。
嬉しいことに目標となるプログラムに近づいておりまして、
自分なりに試行錯誤している状態です。

 次回で完成形になると思いますので、もう少しお付き合いください。
テキストを引数にする手段はなるほど!なのですが、前回少し記入した「複数文字」
の変換の場合はそのテキストを複数用意して入れていくべきでしょうか?
例としてですが、入力値が123の場合、1をAへ。2をBへ。3をCへ変換し、
それぞれの組み合わせ。また、123の場合Cの可能性があるという状定義なのです。
(つまりCの可能性は3単体と123の場合)
上記のため、3文字の抽出用テキストを作り、改めてsubstrで3文字用、
それ以外に複数文字用のものを作り、順次読み込むという煩雑な方法しか無いでしょうか?

 あと、回答としては大文字A~Z、0~9しか在りえず、必ず36種類で
構成されます。
(入力に記号があっても、回答に記号はありません。すいません、
これを最初に書くべきだったかもしれません。)
この定義で前記の例を元にするなら、書いていただいたプログラムの
$keyにCを入れ$valに”3”や”123”を入れることが出来るでしょうか?
$valが固定長でないので、やっぱり複数テキストファイルが必要でしょうか?
よろしくお願いします。

お礼日時:2015/01/08 00:28

>%conv = ~


>の中に入れる変換文字列がとても多いのです。
>1~9、A~Z、記号等を全て別の文字に置き換えるような状態なのです。
>(base64みたいな状態と言えばわかっていただけるでしょうか?
>ただし規則性はありません。暗号みたいなモノです。
>おまけに複数文字列もあるのです。)
>あと、例えばですが1の置換がAかZかどちらもあり得るのです。
>1の回答が複数ある状態です。

これは、具体的には、どのように与えられるのですか?
例えば、CSVファイルのように
1,A
2,B
3,C
のように記述されたファイルがあり、それを読み込んで%convを作り上げることは
簡単にできます。

>おまけに複数文字列もあるのです。)
この意味は、
123をxyz
に変換するというような意味でしょうか?
その場合、
1をA
2をB
3をC
123をxyz

に変換するように指定された場合、123の文字はどのように変換すればよいのでしょうか?
(このケースは考慮しなくてよいのでしょうか?)
また、変換前と変換後の文字列の長さが異なる場合もあるのでしょうか?
例えば、
5をxyz
abcを2
に変換する等です。
    • good
    • 0

#3,#4,#6,#7です。


投稿したソースが
「現在、この回答はサポートで内容を確認中です。
ご迷惑おかけいたしますが、今しばらくお待ちください。」
となり、画面に表示されないので、
参考URLにソースを貼り付けました。
詳細は、参考URLを参照ください。ソースの先頭3行は、あなたのソースを使用させていただきました。
そのソースでの実行結果は、以下の通りです。

入力してください->1A2B3C1x2y4
32 通りの組合せがあります
1A2B3C1x2y4
1A2B3C1xBy4
1A2B3CAx2y4
1A2B3CAxBy4
1A2BCC1x2y4
1A2BCC1xBy4
1A2BCCAx2y4
1A2BCCAxBy4
1ABB3C1x2y4
1ABB3C1xBy4
1ABB3CAx2y4
1ABB3CAxBy4
1ABBCC1x2y4
1ABBCC1xBy4
1ABBCCAx2y4
1ABBCCAxBy4
AA2B3C1x2y4
AA2B3C1xBy4
AA2B3CAx2y4
AA2B3CAxBy4
AA2BCC1x2y4
AA2BCC1xBy4
AA2BCCAx2y4
AA2BCCAxBy4
AABB3C1x2y4
AABB3C1xBy4
AABB3CAx2y4
AABB3CAxBy4
AABBCC1x2y4
AABBCC1xBy4
AABBCCAx2y4
AABBCCAxBy4

不明点があれば、補足ください。

参考URL:http://climbi.com/b/3345/0
    • good
    • 0
この回答へのお礼

ありがとうございました。
何度も投稿していただいたようで、大変助かりました。

さて、プログラムは正月勉強してみました(笑
1文字置換されたら@arreyに回答を入れて、再度読み出して置換して・・・という
パターンを使っているという点は理解できました。
全部の変数をprintしてやっと理解できましたw
簡単なperlしか知らなかったので、大変勉強になりました。

 考えているプログラムにもうすぐ行き着きそうですが、
もう少しだけ甘えさせてください。
途中でも少し説明を書いたのですが、
%conv = ~
の中に入れる変換文字列がとても多いのです。
1~9、A~Z、記号等を全て別の文字に置き換えるような状態なのです。
(base64みたいな状態と言えばわかっていただけるでしょうか?
ただし規則性はありません。暗号みたいなモノです。
おまけに複数文字列もあるのです。)
あと、例えばですが1の置換がAかZかどちらもあり得るのです。
1の回答が複数ある状態です。

回答は不可逆ですから、回答から元に戻せなくても良いのです。

 私が考えているのは、いただいたプログラムで、最初の入力文字に対して
文字を一つずつチェックし、必要なフラグを立て、変換する文字がある場合は
その指定した%conv =~ を使うようなループに移動させるモノにしようと
思っているのですが、どうでしょうか?
ちょっと煩雑になりそうですが、もし良かったらそのアドバイスも
いただけないかなぁと思っております。

お礼日時:2015/01/03 23:34

#3,#4,#6です。


「現在、この回答はサポートで内容を確認中です。」
で保留中の為、もう一度トライします。
以下のようにしてください。
--------------------------------------------------
print "入力してください->";
chomp($inp1 = <STDIN>);
$cont1 = length($inp1);
@array = ();
push @array,$inp1;
%conv = ("1","A","2","B","3","C");
for ($i = 0; $i < $cont1;$i++){
$cont2 = scalar(@array);
for ($j = 0; $j < $cont2; $j++){
$temp = $array[$j];
$char = substr($temp,$i,1);
if (exists $conv{$char}){
substr($temp,$i,1) = $conv{$char};
push @array,$temp;
}
}
}
@array = sort(@array);
printf("%d 通りの組合せがあります\n",scalar(@array));
foreach $str (@array){
print $str,"\n";
}
---------------------------------------------
実行結果は、以下の通りです。
入力してください->1A2B3C1x2y
32 通りの組合せがあります
1A2B3C1x2y
1A2B3C1xBy
1A2B3CAx2y
1A2B3CAxBy
1A2BCC1x2y
1A2BCC1xBy
1A2BCCAx2y
1A2BCCAxBy
1ABB3C1x2y
1ABB3C1xBy
1ABB3CAx2y
1ABB3CAxBy
1ABBCC1x2y
1ABBCC1xBy
1ABBCCAx2y
1ABBCCAxBy
AA2B3C1x2y
AA2B3C1xBy
AA2B3CAx2y
AA2B3CAxBy
AA2BCC1x2y
AA2BCC1xBy
AA2BCCAx2y
AA2BCCAxBy
AABB3C1x2y
AABB3C1xBy
AABB3CAx2y
AABB3CAxBy
AABBCC1x2y
AABBCC1xBy
AABBCCAx2y
AABBCCAxBy

不明点は、補足ください。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!