1時間ごとに更新!Amazon.co.jpで今売れている本トップ100   掲示板ランキング



掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板1

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.5727

テキスト内の()の中の文字列を置き換えたい
投稿者---コム(2006/05/16 15:21:20)


はじめまして。

○○情報(○○企画(東京都)を経営)内にある1階事務所。
○○会社(○○企画()を経営)内にあるロビー。
・・・・・・・・・
・・・・・・・・・

このような内容のテキストファイルを読み込んで
括弧内の文字を文字数分を*やスペースなどに置き換えて
違うテキストに出力したいのですが、

---------------------------------------------------------
例:
○○情報(○○企画(東京都)を経営)内にある1階事務所。
       ↓
○○情報( )内にある1階事務所。
---------------------------------------------------------

どういう方法を取ればスムーズにできるのかわかりません。
よろしくお願いします。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:テキスト内の()の中の文字列を置き換えたい 5728 shu 2006/05/16 16:22:45
<子記事> Re:テキスト内の()の中の文字列を置き換えたい 5729 si 2006/05/16 16:27:57
<子記事> Re:テキスト内の()の中の文字列を置き換えたい 5730 Yuki 2006/05/16 18:00:51
<子記事> Re:テキスト内の()の中の文字列を置き換えたい 5733 nop 2006/05/17 08:59:28
<子記事> Re:テキスト内の()の中の文字列を置き換えたい 5734 breakwind4u 2006/05/17 11:33:26
<子記事> Re:テキスト内の()の中の文字列を置き換えたい 5739 かずま 2006/05/17 16:14:05
<子記事> Re:テキスト内の()の中の文字列を置き換えたい 5765 コム 2006/05/22 15:31:45


No.5728

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---shu(2006/05/16 16:22:45)


考え方

文字列の前から(をさがす。
文字列の後ろから)をさがす。
)が見つかった場所から、(が見つかった場所の差が、括弧内の文字数。

・・・・・・全角・半角・文字コードについては、考えていません。


この投稿にコメントする

削除パスワード

No.5729

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---si(2006/05/16 16:27:57)


>○○情報(○○企画(東京都)を経営)内にある1階事務所。
>○○会社(○○企画()を経営)内にあるロビー。
>括弧内の文字を文字数分を*やスペースなどに置き換えて
一番簡単と思われる方法

まず、日本語の()を、アスキーの()に変換、その後、regexで、パターンマッチ
を繰り返し、()内を変換していく

while (fgetsでバッファ読み込み) {
 s = buf;
 s=strstr(s,"(");
 while(s) {
  ( => ( 変換
  s=strstr(s,"(");
 }
 s = buf;
 s=strstr(s,")");
 while(s) {
  ) => ) 変換
  s=strstr(s,")");
 }
 バッファをどっかに保存
}
char *pat = "\\([^\\(]+\\([^\\)]*\\)[^\\)]+\\)";
int i,nmatch = 1;
regex_t reg;
regmatch_t match[nmatch];
if (regcomp(&reg,pat,REG_EXTENDED) == 0) {
 while(regexec(&reg,変換した文字列,nmatch,match,0) == 0) {
  変換した文字列[match[0].rm_so] <= がマッチした ( の位置
  変換した文字列[match[0].rm_eo]<= がマッチした )の位置
  この間を変換すれば良い。

  変換した文字列 += match[0].rm_eo; <= 次を検索
 }
} else {
 printf("regcomp error\n");
}


この投稿にコメントする

削除パスワード

No.5730

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---Yuki(2006/05/16 18:00:51)


>どういう方法を取ればスムーズにできるのかわかりません。
>よろしくお願いします。

スムーズでない(と思われる)やり方はできているのですか?
もしできているのでしたら、それを公開したほうが
どこを直したほうがスムーズになるよ等のアドバイスできるのですが。
#もしかしたら、既にスムーズなやり方ができているかもしれません。



この投稿にコメントする

削除パスワード

No.5733

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---nop(2006/05/17 08:59:28)


>このような内容のテキストファイルを読み込んで
>括弧内の文字を文字数分を*やスペースなどに置き換えて
>違うテキストに出力したいのですが、

エディタで置換すればよいのでは?


この投稿にコメントする

削除パスワード

No.5734

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/17 11:33:26)


shuさん:
> 文字列の前から(をさがす。
> 文字列の後ろから)をさがす。

最長一致法ですね。

この方法だと、"foo (hoge) bar (fuga) baz" が
"foo (***************) baz" に変換されてしまいます。
恐らく、欲しい結果は"foo (****) bar (****) baz"だと
思います。

siさん:
> まず、日本語の()を、アスキーの()に変換、その後、
> regexで、パターンマッチを繰り返し、()内を変換していく

「全角括弧を半角括弧に変更してよい」という条件を勝手に
追加してよいものかと。また、複数行にまたがる括弧の扱いが
厄介です。(これまた)恐らく、改行文字については括弧に
はさまれていても変換したくないのでは?

nopさん:
> エディタで置換すればよいのでは?

たぶん不可能です。「マッチした文字列の文字数と同数の
スペースか*に置き換え」が目的ですが、正規表現では
できません。そのような置換が可能なエディタをご存知
でしたらご教示願います。

Yukiさん:
> スムーズでない(と思われる)やり方はできているのですか?

上記のように奥が深い問題ですので、「スムーズでないやり方」
すらできないのも無理はありません。暖かく見守りましょう :-)

--------
その上でコムさんに提案ですが、変換前の文字列と変換後の
文字列の例を、なるべくたくさん列挙してみてください。

現在は、括弧が入れ子になっている場合、一番外の括弧の中身を
全てスペースに置き換える例が示されています。

・1行の中に括弧が複数回ある場合はどうか?
・括弧が複数行にまたがる場合はどうか?
・開き括弧が全角で閉じ括弧が半角だった場合どうするか?
・顔文字 (^^; の扱いは? :-)
その他諸々、上記に含まれないような例も色々と考えてみて下さい。











この投稿にコメントする

削除パスワード

No.5735

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---nop(2006/05/17 12:22:36)


>> エディタで置換すればよいのでは?
>たぶん不可能です
>そのような置換が可能なエディタをご存知でしたらご教示願います。

「エディタ」と言うのは一種の例えのつもりでしたが、
わざわざ文字列操作に癖のあるCでやる必要はないのでは?
と言う事です。

# ついでに、「秀丸」なら秀丸マクロで対応可能かと。
# あとは、正規表現による置換が可能なソフトを探したり、
# Perlなどの文字列操作に長けた言語で行うなど、
# した方が良いかと。


この投稿にコメントする

削除パスワード

No.5737

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/17 14:58:14)


># ついでに、「秀丸」なら秀丸マクロで対応可能かと。
># あとは、正規表現による置換が可能なソフトを探したり、
># Perlなどの文字列操作に長けた言語で行うなど、
># した方が良いかと。

このような問題を正規表現で扱うのって、とても難しい問題です。
perl で書いたとしても難しいことに変わりありません。
http://www.hyuki.com/dig/paren.html

同じく難しいのであれば、使い慣れた(かはどうかは知りませんが)
Cで書くのが得策ではないかと思います。

ちょうど以下に似たような話題が上っています。
http://www2.realint.com/cgi-bin/tarticles.cgi?pointc+26738

これをベースに、stack_is_empty() であれば入力した文字を出力、
そうでなければ'*'を出力する、というのがよさげです。

あとは、多バイト文字対応と、括弧が整合しないときの扱いを
決定すれば、コードが完成します。



この投稿にコメントする

削除パスワード

No.5740

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---nop(2006/05/17 16:40:38)


>このような問題を正規表現で扱うのって、とても難しい問題です。
>perl で書いたとしても難しいことに変わりありません。

Perlなら、置換部分は一行で出来ましたが?

----------<Perlでの例>------------------------------
$test = 'Hoge (hoge) hoge';
$result = $test;
$result =~ s/(\()(.+?)(\))/($1).('*' x length($2)).($3)/eg;

print '元 : '.$test."\n";
print '後 : '.$result."\n";

----------------------------------------------------


この投稿にコメントする

削除パスワード

No.5742

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/17 17:11:08)


> Perlなら、置換部分は一行で出来ましたが?

できていないようですが?

$test = (ab(c))
$result = (****))

$test = (a(b)c)
$result = (***)c)

$test = (a(b)c)
$result = (***)c)

$test = ((a)b(c))
$result = (**)b(*))

$test = ((ab)c)
$result = (***)c)

$test = ((a(b))c)
$result = (****))c)

$test = (X(a(b))c)
$result = (*****))c)

$test = abc((()a((b))c))def
$result = abc(**)a(**))c))def



この投稿にコメントする

削除パスワード

No.5743

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/17 17:44:21)


内側の括弧から攻めていって、最後に大外の括弧を
元に戻すのが簡単そうです。

print "\$test = $test\n";
while ($result =~ s/\(([^\(\)]*?)\)/'*' x (length($1) + 2)/eg) {
print "\$result = $result\n";
}
$result =~ s/\*(\*+)\*/($1)/g;
print "\$result = $result\n";

--------
$test = abc((()a((b))c))def
$result = abc((**a(***)c))def
$result = abc((**a*****c))def
$result = abc(***********)def
$result = abc*************def
$result = abc(***********)def

#注1) 変換元の文字列に "**"が含まれていないのが前提です。
#注2) 複数行にまたがる括弧には対応できていません。
#注3) perl には明るくないのであしからず。



この投稿にコメントする

削除パスワード

No.5744

ダメだこりゃ
投稿者---breakwind4u(2006/05/17 17:55:41)


括弧が連続する(場合)(適切に)(処理)できませんでした。
また、中身のない括弧()も処理できませんでした。

よく確認しないまま投稿してしまい、申し訳ありません。

print "\$test = $test\n";
while ($result =~ s/\(([^\(\)]*?)\)/'{'.('*' x length($1)).'}'/eg) {
    print "\$result = $result\n";
}
$result =~ s/\{(\**)\}/($1)/g;
print "\$result = $result\n";


#注1) 変換元の文字列に'{'ならびに'}'が含まれていないことが前提です。
#その他の注は先ほどと同じです。


この投稿にコメントする

削除パスワード

No.5736

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---shu(2006/05/17 14:34:12)


>最長一致法ですね。

そんなかたくるしい名前は、あっても使わないようにします。

>恐らく、欲しい結果は"foo (****) bar (****) baz"だと
>思います。

そうは、思いません。


この投稿にコメントする

削除パスワード

No.5738

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/17 15:16:58)


>そうは、思いません。

否定はしません。「思う」のは自由ですから。

複数の解釈がある時点で仕様が曖昧であることが明確になったので、
コムさんが仕様を明確にしてくれるまで議論しても無駄ですね。



この投稿にコメントする

削除パスワード

No.5739

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---かずま(2006/05/17 16:14:05)


コンパイラが、新しい VC++ なら、
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    wint_t c;  int n = 0;

    setlocale(LC_CTYPE, "");
    while ((c = getwchar()) != WEOF) {
        if (n > 0 && c == L')') n--;
        putwchar(n==0 || c<' ' ? c : c<0x80 ? '*' : L'*');
        if (c == L'(') n++;
    }
    return 0;
}



この投稿にコメントする

削除パスワード

No.5741

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/17 16:59:36)


> putwchar(n==0 || c<' ' ? c : c<0x80 ? '*' : L'*');

wcwidth 使った方が安全かと。


この投稿にコメントする

削除パスワード

No.5745

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---かずま(2006/05/17 21:17:46)


> wcwidth 使った方が安全かと。

それはそうですが、使える処理系が限定されますね。

getwchar などは、Visual C++ や Borland C++ Compiler で使えますが、
wcwidth は C99 にもなくて、POSIX の規格ですから。

Windows で Shift-JIS を使っている場合、半角片仮名が wchar_t の
0xff61〜0xff9f になるので、それは考慮したほうがいいでしょう。


この投稿にコメントする

削除パスワード

No.5755

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/18 01:39:03)


>それはそうですが、使える処理系が限定されますね。

御意。

ところで、ふと思い出したのですが、PC-9801時代に
「2バイト半角仮名文字(ガなどが半角で表現できる)」に
苦しめられた記憶があります(少なくとも一太郎4.3は
2バイト半角のガを入力するとガガと表示/印刷された)。

wcwidth は正しく解釈できるのかな?

#酔っ払いの戯言でした。


この投稿にコメントする

削除パスワード

No.5765

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---コム(2006/05/22 15:31:45)


データ少なくてすみません。
・ファイルの文字列はすべて全角です。
・()内の()も置き換える。
・()が1個のときも、括弧内に括弧が複数のときもあります。

テキストファイル内はこんな感じです。
----------------------------------------------------------------
あいうえお(かきくけこ(さし(1234)すせそ)たちつてと)なにぬねの
12345(6789)0000
-----------------------------------------------------------------
例:あいうえお( )
  12345( )0000

↓見づらくて、無理やりですが以下のような方法で半角括弧内は置き換えられました。
テキストファイル内は全角括弧なので、それを処理できるように変えたいのですが方法がわかりません。

#include <stdio.h>
#include <string.h>

#define BUFFSIZE 1024 //バッファマックスサイズ

void main(void){
    
    int st_flag = 0; //括弧取り外しフラグ
    int c=0;
    char buf[BUFFSIZE];
    FILE *fp;
    int p;
    int count =0;
    fp = fopen("sample.txt","a+");
    
    
    if(fp){
        printf("ファイル読み込み完了");
        p = fgetc(fp); //ファイルから1文字読み込み
        while(feof( fp ) == 0){//ループ
            if(p == '('){ //バッファに'('があると
                c++;                //括弧再開フラグ
                st_flag++;      //括弧取り外しフラグをインクリメント
            } else {
                if(p == ')'){//バッファに')'があるとき                
                    st_flag--;      //括弧取り外しフラグをデクリメント
                    if(st_flag == 0){
                        c = 0;    //括弧再開フラグを戻す
                    }
                }
            }
            
            if(st_flag > 0){
                buf[count] = ' ';
                if(c == 1){
                    buf[count] = '(';
                    c++;
                }
            } else{
                buf[count] = p;
            }
            count++;
            p = fgetc(fp);
        }
        buf[count] = '\n';
        printf("%s",buf);
        
    }else{
        printf("ファイル読み込みエラー");
    }
    fclose(fp);
    
    
    
}




この投稿にコメントする

削除パスワード

No.5766

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---shu(2006/05/23 00:29:37)


>テキストファイル内はこんな感じです。
>----------------------------------------------------------------
>あいうえお(かきくけこ(さし(1234)すせそ)たちつてと)なにぬねの
>12345(6789)0000
>-----------------------------------------------------------------
>例:あいうえお(                                      )
>  12345(         )0000

例での、"あいうえお(                                      )"は、
"あいうえお(                                          )なにぬねの"、
ではないのか?

括弧が半角になっています。「文字列は全て全角」という情報と反します。

1行、1データという考えで良いのか?



この投稿にコメントする

削除パスワード

No.5767

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---コム(2006/05/23 11:02:30)


半角でプログラム作っていた時の情報のまま載せてしまいました、すみません。

1行1データです。後顔文字などはありません。


この投稿にコメントする

削除パスワード

No.5769

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---shu(2006/05/23 14:57:29)


//
//	不完全で、非効率だけども、読んでもらいたいサンプル
//

//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//
int main( void )
{
    FILE *fp;
    char buf[BUF_SIZ];
    int i, start, end;
    
    //
    fp = fopen( "sample.txt", "r" );
    if (fp == NULL)
    {
        perror("ファイルが開けない!");
        exit( 1 );
    }
    
    //
    while (fgets( buf, sizeof(buf), fp ))
    {
        //
        for (i = 0; buf[i]; i++)
            if (strncmp( &buf[i], "(", 2 ) == 0)
                break;
        start = i;
        
        //
        for (i = 0; buf[i]; i++)
            if (strncmp( &buf[i], ")", 2 ) == 0)
                break;
        end = i;
        
        //
        for (i = start + 2; i < end; i++)
            buf[i] = ' ';
        
        //
        fputs( buf, stdout );
    }
    
    return 0;
}



この投稿にコメントする

削除パスワード

No.5770

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/23 17:52:20)


#毎度、茶々ばかりで申し訳ありません。

・JISの場合

文字列リテラル"("の最初の2バイトは、きっと 0x1b, '$' に
なっています。strncmp の結果は恐らく不幸なものです。


・EUCの場合

文字列リテラル"("は 0xA1, 0xCA になります。
これは、例えば "A文" (0xA6, 0xA1, 0xCA, 0xB8) の
2〜3バイト目と同じであり、不幸な結果となります。


・SJISの場合

文字列リテラル"("は、0x81, 0x69 となります。
例えば "=i"(0x81, 0x81, 0x69) の 2〜3バイト目と同じ
であり、不幸な結果となります。

> ・ファイルの文字列はすべて全角です。

この前提があるので、大丈夫と言えば大丈夫なのですが。



この投稿にコメントする

削除パスワード

No.5768

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---breakwind4u(2006/05/23 11:47:29)


1) 処理単位

コムさんの方法だと、扱えるファイルサイズの上限 == BUFFSIZE と
なってしまいます。一行ずつ処理する方法もありますが、一行の
文字数に制限を加えるのもよろしくありません。

今回の場合、かずまさんの方法のように、一文字ずつ逐一出力して
いくのが良い方法でしょう。

http://www3.realint.com/cgi-bin/tarticles.cgi?pointc2+5739


2) 全角対応

> なるべく詳しく環境などの情報をお書きください。
> お使いのコンパイラ、OSによって回答が変わってきます。

環境がいまだ明らかになっていませんので、なんとも答えられません。

wchar が使えるのであれば、かずまさんの方法が良いかと思います。

使えない場合、文字コードを限定して(シフトJISとか)自力で括弧を
判定する必要があります。シフトJISの判定は若干クセがありますので、
以下の URL を参考にしてみて下さい。

http://f1.aaa.livedoor.jp/~pointc/log312.html

入力は全て全角で、改行コードはCR+LFとう前提であれば、2バイトずつ
処理してしまうのも手かも知れません。



この投稿にコメントする

削除パスワード

No.5771

Re:テキスト内の()の中の文字列を置き換えたい
投稿者---かずま(2006/05/24 02:25:26)


>    fp = fopen("sample.txt","a+");

fopen で "a+" を指定するのはどうしてですか?

なぜ、環境を書いてくれないのでしょうか?
wchar は使えないのでしょうか?
Windows なら Shift-JIS だから、次のようなプログラムでよいのでは?

#include <stdio.h>

int iskanji(unsigned char c) { return (c ^ 0x20) - 0xa1u < 60; }

int main(void)
{
    const int LP = 0x8169, RP = 0x816a;  int c, n = 0;
    FILE *fp = fopen("sample.txt", "r");
    if (!fp) return fprintf(stderr, "file open error\n"), 1;

    while ((c = getc(fp)) != EOF) {
        if (iskanji(c)) c = (c<<8) | getc(fp);
        if (c == RP && n > 0) n--;
        if (c < ' ' || n == 0) (c>>8) && putchar(c>>8), putchar(c);
        else (c>>8) && putchar('*'), putchar('*');
        if (c == LP) n++;
    }
    fclose(fp);
    return 0;
}



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧





掲示板提供:(有)リアル・インテグリティ