2

二重引用符内のスペースをそのままにして、スペースと二重引用符をパイプ(||)に置き換える方法を見つけようとしています。

たとえば、「word "wordword"word」のようなものを「word||wordword || word」に、「wordwordword」のようなものを「word|| word||word」に変換します。

今、私はこれを解決するために持っています:

[%- MACRO typestrip(value) PERL -%]
my $htmlVal = $stash->get('value');
$htmlVal =~ s/"/||/g;
print $htmlVal
[%- END -%]

二重引用符をパイプに置き換えるのは問題ありません。

私はプログラミングの実際のバックグラウンドがなく、Perlを使ったことがありますが、これまでこのようなことはなかったので、これがどれほど単純または複雑であるか、あるいはそれが可能かどうかさえわかりません。私はこれをうまく説明できていません。

4

4 に答える 4

9

Text::ParseWordsコアモジュールを使用して、引用符で囲まれていない空白を分割してから、パイプで「単語」を再結合する方が簡単かもしれないと思います。

#!/usr/bin/env perl

use warnings;
use strict;

use Text::ParseWords;

while (my $line = <DATA>) {
  print space2pipes($line); 
  print "\n";
}

sub space2pipes {
  my $line = shift;
  chomp $line;
  my @words = parse_line( qr/\s+/, 0, $line );
  return join '||', @words;
}

__DATA__
word "word word" word
word word word

これをテンプレートエンジンに入れることは、読者の練習問題として残されています:-)

于 2012-06-27T18:31:54.477 に答える
4

これは、PerlFAQのセクション4で回答されたよくある質問に関連しています。

[文字]内を除いて、[文字]で区切られた文字列を分割するにはどうすればよいですか?

Text :: BalancedText :: CSVText :: CSV_XSText :: ParseWordsなど、いくつかのモジュールでこの種の解析を処理できます。

カンマ区切りの文字列を別のフィールドに分割しようとする例を見てみましょう。split(/,/)カンマが引用符で囲まれている場合は分割しないでください。使用できません。たとえば、次のようなデータ行を考えます。

SAR001、 ""、 "Cimetrix、Inc"、 "Bob Smith"、 "CAM"、N、8,1,0,7、 "エラー、コアダンプ"

引用符の制限により、これはかなり複雑な問題です。ありがたいことに、 Mastering RegularExpressionsの著者であるJeffreyFriedlが、これらを処理してくれます。彼は提案します(あなたの文字列がに含まれていると仮定して$text):

my @new = ();
push(@new, $+) while $text =~ m{
           # groups the phrase inside the quotes
             "([^\"\\]*(?:\\.[^\"\\]*)*)",?
           | ([^,]+),?
           | ,
     }gx;
push(@new, undef) if substr($text,-1,1) eq ',';

引用符で区切られたフィールド内で引用符を表す場合は、バックスラッシュでエスケープします("like \"this\"":) 。

あるいは、Text :: ParseWordsモジュール(標準のPerlディストリビューションの一部)では、次のように言うことができます。

use Text::ParseWords;
@new = quotewords(",", 0, $text);

ただし、CSVの解析または生成には、自分で実装するのではなく、Text::CSVを使用することを強くお勧めします。何年にもわたって本番環境ですでに試行およびテストされているコードを使用するだけで、後で発生する奇妙なバグを回避できます。

あなたの状況にテクニックを適応させることは

my $htmlVal = 'word "word word" word';

my @chunks;
push @chunks, $+ while $htmlVal =~ m{
    "([^\"\\]*(?:\\.[^\"\\]*)*)"
  | (\S+)
}gx;

$htmlVal = join "||", @chunks;
print $htmlVal, "\n";

出力:

ワード||ワードワード||ワード

振り返ってみると、これは、 MarkDominusによる正規表現マスタリーで吹き替えられたRandalのルールの適用であることがわかります。

ランダルのルール

キャプチャを使用するかm//g、保持したいものがわかっている場合に使用します。

split捨てたいものがわかっているときに使用します。

ランダル・シュワルツ

あなたの状況では、あなたはあなたが何を残したいのかを知っているので、m//g引用符で囲まれたテキスト、または空白で区切られたテキストに固執するために使用してください。

于 2012-06-27T19:23:43.550 に答える
1

Joelの答えは問題shellwordsありませんが、特に行をトークン化するために使用することで、状況を少し単純化できます。

#!/usr/bin/env perl

use strict; use warnings;
use Text::ParseWords qw( shellwords );

my @strings = (
    'word "word word" word',
    'word "word word" "word word"',
);

@strings = map join('||', shellwords($_)), @strings;

use YAML;
print Dump \@strings;

たくさんの正規表現-gobbledygookよりも読みやすいのではないですか?

于 2012-06-28T13:12:11.943 に答える
0

可能であるように思われ、正規表現のみが適用可能な場合に役立つ可能性があります。

 $htmlVal =~ s/(?:"([^"]+)"(\s*))|(?:(\S+)(\s*))/($1||$3).($2||$4?'||':'')/eg;

(詳しく調べた後、少し美しくなる可能性があります。)

入力:

 my $htmlVal ='word "word word" word';

出力:

 word||word word||word


この場合に失敗した後、元のコードが変更されました。

 my $htmlVal ='word "word word" "word word"';

これで動作します:

 word||word word||word word


説明:

 $htmlVal =~ s/
               (?: " ([^"]+) " (\s*)) # search "abc abc" ($1), End ($2)
               |                      # OR
               (?: (\S+) (\s*))       # abcd ($3), End ($4)
              /
               ($1||$3) . ($2||$4 ? '||' : '') # decide on $1/$2 or $3/$4 
              /exg;

よろしく

rbo

于 2012-06-27T19:03:06.803 に答える