2

嗨,我正在尝试制作一个接收 CSV 文件的函数,然后将其插入到文件中,但它可以正常工作,但不是我需要它做的事情。

目前我正在使用explode从文件中获取行..

explode(",", $linearray);

这有效,但如果有类似的东西

field1,field2,field3,field4,"some text, some other text",field6

我得到这个数组

array(
[0]=>field1,
[1]=>field2,
[2]=>field3,
[3]=>field4,
[4]=>"some text,
[5]=>some other text",
[6]=>field6
)

这不是我想要的结果。我知道 preg_split 可以为我做,但我不擅长正则表达式。我想要的结果是。

field1,field2,field3,field4,"some text, some other text",field6

array(
[0]=>field1,
[1]=>field2,
[2]=>field3,
[3]=>field4,
[4]=>some text, some other text,
[5]=>field6
)

请帮忙。

我编写的 PHP 类中的 CSV 文件的函数

    $lineseparator = "\n";
    $fieldseparator = "\n";

function ReadFile(){
    $this->csvcontent = fread($this->_file,$this->size);
    fclose($this->_file);
    return ($this->csvcontent)? true : false ;
}
function InsertFileToSQL(){
    $query = "";
    $i_count = 0;
    $queries = "";
    $linearray = array();
    $file_array = explode($this->lineseparator,$this->csvcontent);
    $lines = count($file_array);
    foreach($file_array as $key => $value) {
        $value = trim($value," \t");
        $value = str_replace("\r","",$value);
        /***********************************************************************************************************
        This line escapes the special character. remove it if entries are already escaped in the csv file
        ************************************************************************************************************/
        $value = str_replace("'","\'",$value);
        $value = str_replace("\"","",$value);
        /***********************************************************************************************************/

        $linearray = explode($this->fieldseparator,$value);

        foreach($linearray as $key2 => $value2){
            // Format all fields that match a date format the Reformat for SQL.
            $date = explode("/", $value2);
            if(count( $date ) == 3 ){
                $linearray[$key2] = $date[2]."-".$date[1]."-".$date[0];
            }
        }

        $linemysql = implode("','",$linearray);
        if($linemysql != "" && $linemysql != NULL){
            if($this->csvheader ){
                if($key != 0){
                    if($this->addauto == 1){
                        $query = "INSERT INTO `$this->db_table` VALUES (NULL,'$linemysql');";
                    }else{
                        $query = "INSERT INTO `$this->db_table` VALUES ('$linemysql');";
                    }
                }else{
                    $lines--;
                }
                $insert = mysql_query($query) or die(mysql_error());
                if($insert){
                    $queries .= $query . "\n";
                    $i_count++;
                }

            }else{
                if($this->addauto == 1){
                    $query = "INSERT INTO `$this->db_table` VALUES (NULL,'$linemysql');";
                }else{
                    $query = "INSERT INTO `$this->db_table` VALUES ('$linemysql');";
                }
                $insert = mysql_query($query) or die((mysql_error()." in QUERY: ".$query));
                if($insert){
                    $queries .= $query . "\n";
                    $i_count++;
                }

            }
        }else{
            $this->null_row++;
            $lines--;
        }


    }
    if($this->save) {
        $f = fopen($this->output_location.$this->outputfile, 'a+');

        if ($f) {
          @fputs($f, $queries);
          @fclose($f);
        }else{
            echo("Error writing to the output file.", 'error');
        }

    }
    $lines--;//fix array count
    $text = "";
    if($i_count - $this->null_row  != 0){$i_count = $i_count - $this->null_row ;$text .= "<br>$i_count Records were inserted Successfully.";}
    echo("Found a Total of $lines Record(s) in this csv file.<br>$this->null_row Record(s) were/are Blank or Null.$text", 'success');
}
4

3 回答 3

2

我想你的答案在这里:

使用正则表达式分解字符串

正如@Casimir et Hippolyte在该页面中所说:

您可以使用 preg_match_all 完成这项工作

$string="a,b,c,(d,e,f),g,'h, i j.',k";

preg_match_all("~'[^']++'|\([^)]++\)|[^,]++~", $string,$result);
print_r($result[0]);

解释:

诀窍是在括号之前匹配括号,

~          Pattern delimiter
'
[^']       All charaters but not a single quote
++         one or more time in [possessive][1] mode
'
|          or
\([^)]++\) the same with parenthesis
|          or
[^,]       All characters but not a comma
++
~

如果您有多个分隔符(如引号)(打开和关闭相同),您可以使用捕获组这样编写模式:

$string="a,b,c,(d,e,f),g,'h, i j.',k,°l,m°,#o,p#,@q,r@,s";

preg_match_all("~(['#@°]).*?\1|\([^)]++\)|[^,]++~", $string,$result);
print_r($result[0]);

解释:

(['#@°])   one character in the class is captured in group 1
.*?        any character zero or more time in lazy mode 
\1         group 1 content

使用嵌套括号:

$string="a,b,(c,(d,(e),f),t),g,'h, i j.',k,°l,m°,#o,p#,@q,r@,s";

preg_match_all("~(['#@°]).*?\1|(\((?>[^()]++|(?-1)?)*\))|[^,]++~", $string,$result);
print_r($result[0]);
于 2013-05-10T15:45:22.703 回答
0

您可以将 preg_split 与 PREG_SPLIT_DELIM_CAPTURE 选项一起使用。

$str = field1,field2,field3,field4,"一些文本,一些其他文本",field6;

然后像这样

$match = preg_split("ypir expression", $str, null, PREG_SPLIT_DELIM_CAPTURE);
于 2013-05-10T12:29:13.850 回答
0

我不会回答被问到的问题,因为他要求错误的解决方案来解决他的问题。但是,我希望这个解决方案对他来说会更好:

查看问题中的代码,OP 基本上是通过 PHP 读取 CSV 文件并将其导入 mysql 数据库。

MySQL 实际上提供了一种直接使用其LOAD DATA INFILE语法执行此操作的方法,而根本无需在 PHP 中解析文件。它比通过 PHP 处理要快得多,并且完全避免了 OP 遇到的整个问题。

在 PHP 中,您只需要执行以下操作:

$query = <<<eof
  LOAD DATA INFILE {$filename} INTO {$table}
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\r\n'
  IGNORE 1 LINES
  field1, field2, field3, field4, field5, field6
eof;
mysqli_query($conn, $query);

您可能需要针对代码中一些更复杂的内容(即转换日期格式等)稍微修改该查询,但是一旦您掌握了LOAD DATA INFILE语法的窍门,您会发现合并起来相当简单。

我希望这会有所帮助。

于 2013-05-10T13:22:08.570 回答