10

この質問は、構造化テキストファイルを PHP 多次元配列に変換する方法とほぼ同じですが、与えられた正規表現ベースのソリューションを理解できなかったため、再度投稿しました。実際にそれから学ぶことができるように、PHP だけを使用してこれを解決しようとする方が良いようです (この時点で正規表現を理解するのは難しすぎます)。

次のテキスト ファイルがあるとします。

HD Alcoa Earnings Soar; Outlook Stays Upbeat 
BY By James R. Hagerty and Matthew Day 
PD 12 July 2011
LP 

Alcoa Inc.'s profit more than doubled in the second quarter.
The giant aluminum producer managed to meet analysts' forecasts.

However, profits wereless than expected

TD
Licence this article via our website:

http://example.com

このテキストファイルを PHP で読み取ります。次のように、ファイルの内容を配列に入れるための堅牢な方法が必要です。

array(
  [HD] => Alcoa Earnings Soar; Outlook Stays Upbeat,
  [BY] => By James R. Hagerty and Matthew Day,
  [PD] => 12 July 2011,
  [LP] => Alcoa Inc.'s profit...than expected,
  [TD] => Licence this article via our website: http://example.com
)

単語HD BY PD LP TDは、ファイル内の新しいセクションを識別するためのキーです。配列では、すべての改行が値から取り除かれます。理想的には、正規表現なしでこれを行うことができます。すべてのキーで爆発することはそれを行う1つの方法だと思いますが、それは非常に汚いでしょう:

$fields = array('HD', 'BY', 'PD', 'LP', 'TD');
$parts = explode($text, "\nHD ");
$HD = $parts[0];

おそらく一度でもテキストをループして、上記のように配列に分割する方法について、より明確なアイデアを持っている人はいますか?

4

9 に答える 9

5

アップデート :

投稿されたサンプル入力ファイルとコードを考慮して、回答を変更しました。セクションコードを定義し、関数が2桁以上のコードを処理できるようにする、OPが提供する「パーツ」を追加しました。以下は、望ましい結果を生成する正規表現以外の手続き型関数です。

# Parses the given text file and populates an array with coded sections.
# INPUT:
#   filename = (string) path and filename to text file to parse
# RETURNS: (assoc array)
#   null is returned if there was a file error or no data was found
#   otherwise an associated array of the field sections is returned
function getSections($parts, $lines) {
   $sections = array();
   $code = "";
   $str = "";
   # examine each line to build section array
   for($i=0; $i<sizeof($lines); $i++) {
      $line = trim($lines[$i]);
      # check for special field codes
      $words = explode(' ', $line, 2);
      $left = $words[0];
      #echo "DEBUG: left[$left]\n";
      if(in_array($left, $parts)) {
         # field code detected; first, finish previous section, if exists
         if($code) {
            # store the previous section
            $sections[$code] = trim($str);
         }
         # begin to process new section
         $code = $left;
         $str = trim(substr($line, strlen($code)));
      } else if($code && $line) {
         # keep a running string of section content
         $str .= " ".$line;
      }
   } # for i
   # check for no data
   if(!$code)
      return(null);
   # store the last section and return results
   $sections[$code] = trim($str);
   return($sections);
} # getSections()


$parts = array('HD', 'BY', 'WC', 'PD', 'SN', 'SC', 'PG', 'LA', 'CY', 'LP', 'TD', 'CO', 'IN', 'NS', 'RE', 'IPC', 'PUB', 'AN');

$datafile = $argv[1]; # NOTE: I happen to be testing this from command-line
# load file as array of lines
$lines = file($datafile);
if($lines === false)
   die("ERROR: unable to open file ".$datafile."\n");
$data = getSections($parts, $lines);
echo "Results from ".$datafile.":\n";
if($data)
   print_r($data);
else
   echo "ERROR: no data detected in ".$datafile."\n";

結果:

Array
(   
    [HD] => Alcoa Earnings Soar; Outlook Stays Upbeat
    [BY] => By James R. Hagerty and Matthew Day
    [PD] => 12 July 2011
    [LP] => Alcoa Inc.'s profit more than doubled in the second quarter. The giant aluminum producer managed to meet analysts' forecasts. However, profits wereless than expected
    [TD] => Licence this article via our website: http://example.com
)
于 2013-08-23T15:47:26.933 に答える
2

まったくループしないでください。これはどうですか (ファイルごとに 1 つのレコードを想定)。

$inrec = file_get_contents('input');
$inrec = str_replace( "\n'", "'", str_replace( array( 'HD ', 'BY ', 'PD ', 'LP', 'TD' ), array( "'HD' => '", "','BY' => '", "','PD' => '", "','LP' => '", "','TD' => '" ), str_replace( "'", "\\'", $inrec ) ) )."'";
eval( '$record = array('.$inrec.');' );
var_export($record);

結果:

array (
  'HD' => 'Alcoa Earnings Soar; Outlook Stays Upbeat ',
  'BY' => 'By James R. Hagerty and Matthew Day ',
  'PD' => '12 July 2011',
  'LP' => ' 

Alcoa Inc.\'s profit more than doubled in the second quarter.
The giant aluminum producer managed to meet analysts\' forecasts.

However, profits wereless than expected
',
  'TD' => '
Licence this article via our website:

http://example.com',
)

ファイルごとに複数のレコードが存在する可能性がある場合は、次のようなことを試してください。

$inrecs = explode( 'HD ', file_get_contents('input') );
$records = array();
foreach ( $inrecs as $inrec ) {
   $inrec = str_replace( "\n'", "'", str_replace( array( 'HD ', 'BY ', 'PD ', 'LP', 'TD' ), array( "'HD' => '", "','BY' => '", "','PD' => '", "','LP' => '", "','TD' => '" ), str_replace( "'", "\\'", 'HD ' . $inrec ) ) )."'";
   eval( '$records[] = array('.$inrec.');' );
}
var_export($records);

編集

これは $inrec 関数が分割されたバージョンで、より簡単に理解できるようになっています。さらに、いくつかの調整が加えられています: 改行を削除し、先頭と末尾のスペースを削除し、データが信頼できないものからのものである場合に EVAL でバックスラッシュの問題に対処します。ソース。

$inrec = file_get_contents('input');
$inrec = str_replace( '\\', '\\\\', $inrec );       // Preceed all backslashes with backslashes
$inrec = str_replace( "'", "\\'", $inrec );         // Precede all single quotes with backslashes
$inrec = str_replace( PHP_EOL, " ", $inrec );       // Replace all new lines with spaces
$inrec = str_replace( array( 'HD ', 'BY ', 'PD ', 'LP ', 'TD ' ), array( "'HD' => trim('", "'),'BY' => trim('", "'),'PD' => trim('", "'),'LP' => trim('", "'),'TD' => trim('" ), $inrec )."')";
eval( '$record = array('.$inrec.');' );
var_export($record);

結果:

array (
  'HD' => 'Alcoa Earnings Soar; Outlook Stays Upbeat',
  'BY' => 'By James R. Hagerty and Matthew Day',
  'PD' => '12 July 2011',
  'LP' => 'Alcoa Inc.\'s profit more than doubled in the second quarter. The giant aluminum producer managed to meet analysts\' forecasts.  However, profits wereless than expected',
  'TD' => 'Licence this article via our website:  http://example.com',
)
于 2013-08-24T23:08:36.317 に答える