我试图替换用竖线分隔并引用封装文件的引号,而不替换提供封装的引号。
我尝试使用下面的Perl行用反斜杠`替换引号,但不确定如何只替换引号而不替换整个1。
样本数据(test.txt):
"1"|"Text"|"a"\n
"2"|""Text in quotes""|"ab"\n
"3"|"Text "around" quotes"|"abc"\n
perl -pi.bak -e 's/(?<=\|")(.*)(?="\|)/\1`/' test.txt
这是正在发生的事情:
"1"|"`"|"a"\n
"2"|"`"|"ab"\n
"3"|"`"|"abc"\n
这是我想要实现的目标:
"1"|"Text"|"a"\n
"2"|"`Text in quotes`"|"ab"\n
"3"|"Text `around` quotes"|"abc"\n
答案 0 :(得分:3)
在Perl 5.14和更高版本中,您可以使用
perl -pi.bak -e 's/(?:^|\|)(")?\K(.*?)(?=\1(?:$|\|))/$2=~s#"|(`)#`$1#gr/ge' test.txt
这里的要点是您将字段与第一个正则表达式匹配,然后使用在匹配部分运行的第二个正则表达式处理双引号和反引号。
详细信息
(?:^|\|)
-匹配字符串或|
的开头(")?
-与"
匹配的可选第1组\K
-匹配重置运算符会丢弃当前匹配缓冲区中的所有文本(.*?)
-第2组:除换行符外的任何0+个字符(?=\1(?:$|\|))
-一个正向超前查询,可确保与组1中的值相同,然后确保字符串的末尾或|
的位置紧靠当前位置的右侧。因此,第2组是单元格内容,没有用双引号引起来。 $2=~s#"|(
)#$1#gr
用"
替换所有`
,并复制第2组值中所有找到的文字反引号(请参见this regex demo)。 "|(`)
模式与"
或反引号匹配(将后者捕获到组1中),而`$1
则将匹配替换为反引号和组1的内容。
答案 1 :(得分:2)
已更新是为了澄清已经出现的反引号应加倍
一种方法是在split
上的|
上加上引号,使其余的正则表达式变得简单,然后重新组装字符串。与单个正则表达式相比,这可能会失去一些效率,但维护起来要简单得多
perl -F"\|" -wlanE'
say join "\|",
map { s/^"|"$//g; s/`/``/g; s/"([^"]+)"/`$1`/g; qq("$_") } @F
' data.txt
-a
选项使其“自动分割”每一行,因此在程序中,行标记在@F
中可用,而-F
指定要分割的模式(默认值除外) )。 -l
处理换行符。参见Command switches in perlrun。
在map
中,封闭的"
被删除,现有的反引号也加倍;然后全局更改"
模式周围的内容。然后将引号放回去,并编辑返回的列表join
。 |
中的join
被转义,以便通过shell进入Perl程序;如果这是脚本(而不是单行代码),我将始终建议将\|
更改为|
。
我不知道有关报价的典型数据和可能出现的边缘情况,但是如果报价中可能存在松散(单个,不成对)的报价,则会出现问题,并可能产生错误的输出,并且会安静地输出;就像任何期望使用双引号的过程一样,无需进行非常详细的分析。
简单地将所有"
(而不是封闭的)替换为
map { s/^"|"$//g; s/`/``/g; s/"/`/g; qq("$_") }
(或使用tr
代替正则表达式s///g
)。这也增加了一些效率指标。
获取数据“实质”的另一种方法是使用Text::CSV,它允许使用除(缺省)逗号之外的定界符并吸收引号。在字段中使用引号被认为是CSV格式不正确,但是该模块也可以使用以下选项对其进行解析。
use warnings;
use strict;
use feature 'say';
use Text::CSV;
my $file = shift || 'data.txt';
my $outfile = 'new_' . $file;
my $csv = Text::CSV->new( { binary => 1, sep_char => '|',
allow_loose_quotes => 1, escape_char => '', # quotes inside fields
always_quote => 1 # output as desired
} ) or die "Can't do CSV: ", Text::CSV->error_diag;
open my $fh, '<', $file or die "Can't open $file: $!";
open my $out_fh, '>', $outfile or die "Can't open $outfile: $!";
while (my $row = $csv->getline($fh)) {
s/`/``/g for @$row;
tr/"/`/ for @$row;
$csv->say($out_fh, $row);
}
要在字段escape_char
中使用引号,quote_char
必须与''
不同;我只是在这里将其设置为always_quote
。输出也由模块处理,并且class _HomePageState extends State<HomePage> {
List<Todo> _dataList;
final FirebaseDatabase _database = FirebaseDatabase.instance;
StreamSubscription<Event> _onTodoAddedSubscription;
Query _todoQuery;
@override
void initState() {
super.initState();
_dataList = List();
_todoQuery = _database.reference().child(widget.userId);
_onTodoAddedSubscription = _todoQuery.onChildAdded.listen(_onEntryAdded);
}
@override
void dispose() {
_onTodoAddedSubscription.cancel();
super.dispose();
}
_onEntryAdded(Event event) {
setState(() {
_dataList.add(Todo.fromSnapshot(event.snapshot));
});
}
Widget _showTodoList() {
if (_dataList.length > 0) {
return ListView.builder(
shrinkWrap: true,
itemCount: _dataList.length,
itemBuilder: (BuildContext context, int index) {
String todoId = _dataList[index].key;
bool status = _dataList[index].status;
int datetime = _dataList[index].datetime;
double current = _dataList[index].current;
double voltage = _dataList[index].voltage;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _showTodoList(),
);
}
}
属性用于该属性(引用所有字段,无论是否需要)。请参阅文档。
当然,使用此模块可以完成更多工作。
如果问题的目的恰好是清理一种文件格式,其中对字段和字段内部都使用相同的引号,则建议对模块进行全部处理。这种方法使人们可以干净,一致地设置用于输入和输出的各种选项,并且是可维护的。
几个问题
那里有什么样的数据,有可能出现流浪报价?那呢这可能甚至影响最佳方法的选择,因为它可能需要详细的分析。
如果此处的任务是拉直CSV样式的数据,那么为什么不对字段中的引号(如CSV中常见的和正确的)加倍,而不是替换它们(并可能损害其文本含义)?例如,请参阅模块的文档。
答案 2 :(得分:1)
Perl使用$ 1作为正则表达式替换部分中的第一个捕获组的占位符,而不是\ 1(用于正则表达式的匹配部分)。您的正则表达式与内引号不匹配,并且可能与管道分隔数据的第一个或最后一个字段不匹配。您的替换也未能在被捕获的组之前添加引号字符。
尝试:
perl -pi.bak -e 's/(?<=(?:^|\|)")"([^"]*)"(?="(?:$|\|))/`$1´/' test.txt
答案 3 :(得分:0)
另一个Perl。按数组@F拆分后,检查“不在元素开头/结尾的位置。”
perl -F"\|" -lane ' for(@F) { s/(?<!^)"(?!$)/`/g }; print join("|",@F) '
具有给定的输入
$ cat grasshopper.txt
"1"|"Text"|"a"
"2"|""Text in quotes""|"ab"
"3"|"Text "around" quotes"|"abc"
$ perl -F"\|" -lane ' for(@F) { s/(?<!^)"(?!$)/`/g }; print join("|",@F) ' grasshopper.txt
"1"|"Text"|"a"
"2"|"`Text in quotes`"|"ab"
"3"|"Text `around` quotes"|"abc"
$