Regex 替换文件中第一个括号之前的所有连字符

Regex 替换文件中第一个括号之前的所有连字符,regex,perl,sed,pattern-matching,Regex,Perl,Sed,Pattern Matching,我正在尝试使用sed或perl替换第一个实例之前文件中出现的所有连字符) 到目前为止,我有以下内容替换了文件中的所有连字符,但我无法使其仅匹配到“;”的第一个实例 进一步资料: 我正在尝试从已生成的create table SQL中删除无效的连字符,我们有1k+个文件要处理,但我使用的任何连字符都会替换所有连字符 要清除的文本示例: CREATE TABLE e_00_90 ( Last_Name nvarchar(50), Initials nvarchar(3), Company_D

我正在尝试使用sed或perl替换第一个实例之前文件中出现的所有连字符)

到目前为止,我有以下内容替换了文件中的所有连字符,但我无法使其仅匹配到“;”的第一个实例

进一步资料:

我正在尝试从已生成的create table SQL中删除无效的连字符,我们有1k+个文件要处理,但我使用的任何连字符都会替换所有连字符

要清除的文本示例:

CREATE TABLE e_00_90 (
Last_Name nvarchar(50),
  Initials nvarchar(3),
  Company_Division nvarchar(50),
  Status nvarchar(12),
  Ckeyword5 nvarchar(15),
  Value_of_Contract_-_Overh decimal(20,2)
);
insert into export_00_90 values ('Sample-One', 'R', 'Div 1', 'Expired', 'ANONYTR', 5000);
insert into export_00_90 values ('Sample Two', 'R', 'Div_2', 'Expired', 'WISHBONE', 13000);
我只需要创建表块就可以删除连字符。

(?:(?!PAT)。*
是要
PAT
,正如
[^CHAR]
是要
CHAR
,所以

s/\G (?: (?! \); | - ) . )* \K - /_/xsg
备选方案:

s/\G (?: (?! \); ) [^-] )* \K - /_/xg
最快:

s/\G (?: [^)-]++ | \)(?!;) )* \K - /_/xg
使用GNU时:

sed -E ':a;s/^([^)]*)-([^)]*\);)/\1_\2/;ta;'
[编辑]
使用awk:

awk -v RS=');' -v ORS=');' '/^CREATE TABLE/{gsub("-","_")}1'
使用perl:

perl -pe'BEGIN{$/=");"} /^CREATE TABLE/&&y/-/_/'
对于sed:

sed '/^CREATE TABLE/{:;/);/!{N;b};y/-/_/;}'
sed -E ':;s/^(([^)-]|\)[^;-])*\)*)-/\1_/;t'
awk和perl的方法是相同的,它们使用记录分隔符
,检查此字符是否以“createtable”开头,并将每个连字符转换为下划线

sed版本没有太大的不同,只是您需要自己构建文本块,将每一行追加到
。(注意,这种方式假定
之后没有更多的代码)在同一行中):

{
:#定义一个空标签
/);/!(如果);不匹配
{
N#在模式空间中添加换行符
去标签那儿
}
y/-/#翻译
}

[旧答案:只能按行操作]
对于sed:

sed -E ':;s/^(([^)-]|\)[^;-])*\)*)-/\1_/;t'
或者使用perl:

perl -pe's/.*?\);|.+/$&=~y|-|_|r/e'

(这种方式匹配所有,直到第一个
或字符串的结尾,然后使用
y//
)将匹配中的每个连字符转换为下划线。

我不会尝试使用神奇的正则表达式来处理它,而是:

#!/usr/bin/env perl
use strict;
use warnings;

while ( <DATA> ) {
   if ( m/CREATE TABLE/ .. /\);/ ) { 
      s/-/_/g;
   }
   print;
}


__DATA__
CREATE TABLE e_00_90 (
Last_Name nvarchar(50),
  Initials nvarchar(3),
  Company_Division nvarchar(50),
  Status nvarchar(12),
  Ckeyword5 nvarchar(15),
  Value_of_Contract_-_Overh decimal(20,2)
);
insert into export_00_90 values ('Sample-One', 'R', 'Div 1', 'Expired', 'ANONYTR', 5000);
insert into export_00_90 values ('Sample Two', 'R', 'Div_2', 'Expired', 'WISHBONE', 13000);

试试
的/^((?:(?!\);)*)-\)/$1_);/'不错。我不知道您可以在没有标签的情况下使用
t
命令。@SLePort:事实上,您需要一个标签,但这个标签的名称是空的。谢谢。这两种方法似乎都可以将所有连字符转换为下划线,即使是在第一次使用“;”之后的连字符@uint32:我回答了你问题的第一个版本,没有多行示例。因此,我的答案和其他答案都是按行设计的。现在你的问题完全不同了。@Casimir et Hippolyte:谢谢你的意见。很抱歉,我最初的问题并不像应该的那么清楚。
perl -pi -e 'm/CREATE TABLE/ .. /\);/ && s/-/_/g' 00-90.sql