如何使用regex / terminal工具删除csv单元格中的换行符?

时间:2015-11-30 08:26:25

标签: regex perl unix sed terminal

我有一个csv文件,其中一些单元格里面有换行符。例如:

id,name 
01,"this is
with newline"
02,no newline 

我想删除单元格中的所有换行符。

如何使用正则表达式或其他终端工具一般不事先知道列数?

5 个答案:

答案 0 :(得分:6)

这实际上是一个比它看起来更难的问题,在我看来,这意味着regex不是正确的解决方案。因为您正在处理引用/转义字符串,跨越多个“行”,最终会导致复杂且难以阅读#!/usr/bin/env perl use strict; use warnings; use Text::CSV; my $csv = Text::CSV->new( { binary => 1, eol => "\n" } ); while ( my $row = $csv->getline( \*ARGV ) ) { s/\n/ /g for @$row; $csv->print( \*STDOUT, $row ); } 。 (这不是不可能的,它只是凌乱)。

我建议改为 - 使用解析器。 Perl在Text::CSV中有一个,它有点像这样:

\*ARGV

这将在命令行中将文件作为管道输入/指定 - 这是sed所做的 - 它是一个特殊的文件句柄,可以让你...基本上是somecommand.sh | myscript.pl myscript.pl filename_to_process 所做的:

ARGV

自动\*STDIN文件句柄。 (如果您愿意,可以明确打开文件或使用 <table class="table table-bordered" style="width: 80%;margin:5% 10%;background:slateblue"> <tr> <th>#</th> <th>item</th> <th>item name</th> <th>Added_at</th> <tr> <?php $i=1 ?> @foreach($items as $item) <tr> <td><input type="checkbox" id="bought" name="{{$item->item_name}}" class="checkbox1"></td> <td>{{$item->id}}</td> <td>{{$item->item_name}}</td> <td>{{$item->date}} </tr> @endforeach </table> <form class="shopped" method="post" action="{{url('post-data')}}" hidden><br> {!! csrf_field()!!} <h4 align="center">Add some information to mark as shopped</h4> <label for ="item">Items</label> <input type="text" class ="item" disabled><br> <label for ="price">Price</label> <input type="text" name="price"><br> <label for ="store_name">Store</label> <input type="text" name="store_name"><br> <input type="submit" value="Add as purchased" class="btn btn-info" style="margin:20px 0 20px 60px"><br> </form>

答案 1 :(得分:1)

  

如何使用正则表达式或其他终端工具一般不事先知道列数?

我认为正则表达式不是最合适的方法,最终可能会变得非常复杂。相反,我认为从长远来看,处理文件的单独程序可能更容易维护。

由于您可以使用任何终端工具,我选择了python,代码如下:

#!/usr/bin/python3 -B

import csv
import sys

with open(sys.argv[1]) as csvfile:
    reader = csv.reader(csvfile)
    for row in reader:
        stripped = [col.replace('\n', ' ') for col in row]
        print(','.join(stripped))

我认为上面的代码非常简单易懂,无需复杂的正则表达式。

此处的输入文件包含以下内容:

id,name
01,"this is
with newline"
02,no newline

为证明其有效,其输出如下:

➜  ~  ./test.py input.csv
id,name
01,this is with newline
02,no newline

您可以从其他程序调用python脚本并将文件名提供给它。你只需要为python程序添加一个小更新来写出文件,如果那是你真正需要的。

我已经用空格替换换行符以避免可能不需要的连接(例如this iswith newline),但您可以用您想要的任何内容替换换行符,包括空字符串''

答案 2 :(得分:1)

我怀疑不是删除换行符,而是实际上想要用空格替换换行符。如果您的输入文件看起来很简单,那么应该为您完成:

$ awk '{ORS=( (c+=gsub(/"/,"&"))%2 ? FS : RS )} 1' file
id,name
01,"this is with newline"
02,no newline

答案 3 :(得分:0)

我写了一个方法来删除单元格中嵌入的新行。下面的方法返回一个java.util.List对象,该对象包含CSV文件中的所有行

List<String> getAllRowsInCSVFileAsList(File selectedCSVFile){
  FileReader fileReader = null;
  BufferedReader reader = null;
  List<String> values = new ArrayList<String>();
  try{
      fileReader = new FileReader(selectedCSVFile);
      reader = new BufferedReader(fileReader);
      String line = reader.readLine();
      String previousLine = "";
      //
      boolean intendLineInCell = false;
      while(line != null){
          if(intendLineInCell){
              if(line.indexOf("\"") != -1 && line.indexOf("\"") == line.lastIndexOf("\"")){
                  previousLine += line;
                  values.add(previousLine);
                  previousLine = "";
                  intendLineInCell = false;
              } else if(line.indexOf("\"") != -1 && line.indexOf("\"") != line.lastIndexOf("\"")){
                  if(getTotalNumberOfCharacterSequenceOccurrenceInString("\"", line) % 2 == 0){
                      previousLine += line;
                  }else{
                      previousLine += line;
                      values.add(previousLine);
                      previousLine = "";
                      intendLineInCell = false;
                  }
              } else{
                  previousLine += line;
              }
          }else{
              if(line.indexOf("\"") == -1){
                  values.add(line);
              }else if ((line.indexOf("\"") == line.lastIndexOf("\"")) && line.indexOf("\"") != -1){
                  intendLineInCell = true;
                  previousLine = line;
              }else if(line.indexOf("\"") != line.lastIndexOf("\"") && line.indexOf("\"") != -1){
                  values.add(line);
              }
          }
          line = reader.readLine();
      }
  }catch(IOException ie){
      ie.printStackTrace();
  }finally{
      if(fileReader != null){
          try {
              fileReader.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
      if(reader != null){
          try {
              reader.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
      }
  }
  return values;

}

int getTotalNumberOfCharacterSequenceOccurrenceInString(String characterSequence, String text){
  int count = 0;
  while(text.indexOf(characterSequence) != -1){
      text = text.replaceFirst(characterSequence, "");
      count++;
  }
  return count;

}

想象一下,您正在创建一个包含一行和五列的csv文件,在第四个单元格中,您有一个嵌入的新行(在单元格内输入)

您的数据将如下所示(实际上我们在csv中只有一行,但如果您在记事本中打开它,它将看起来像2行)。

dinesh,kumar,24,"23 
tambaram india",green

如果单元格内部有输入,则可能如下所示

"23
tambaram india"

该单元格以双引号(&#34;)开头,以双引号结束(&#34;)。

如果有双引号(&#34;),在阅读该行的同时使用双引号(&#34;),我们可以理解单元格中有嵌入的输入。

代码用该行连接下一行并检查是否有结束双引号(&#34;)。如果有,它会在java.util.List对象中添加一个新行,否则它将连接下一行并检查它是否为结束双引号(&#34;),依此类推。这里我已经解释了一个单元格,但是如果行中有很多嵌入了enter的单元格,该方法也可以工作。

答案 4 :(得分:-2)

使用notepadd ++打开* csv文件,然后按Ctrl + H.转到选项卡替换并输入搜索框“换行”,然后写入以替换要替换的单词,或者如果需要,将其清空。