用Regex提取String的第一个字母

时间:2010-07-20 04:09:54

标签: regex

我是RegEx的新手,我希望能够在我的文本文件中搜索和替换特定文本。我能够完成大部分搜索,但是这里有一个我无法理解它的问题。我想我应该使用环顾四周/向前看/看后面。但我正在使用的工具说语法错误。 基本上这里是我文件中的数据

[2010-01-15 06:18:10.203] [0x00001388] [SHDNT]关机倒数= 2/5

[2010-01-15 06:18:11.203] [0x00001388] [SHDNT]关机倒数= 3/5

我希望能够在搜索中捕捉日期周围的'['和']'。我想找到'['使用一些标准,如('['后跟[0-9] [0-9]意思是两位数)和']'和(']'继续'。[0-9] [0-9] [0-9]'含义dot和3digits)。

我尝试了这个,但它给出了错误 \ [(?= [0-9] [0-9])用于第一次搜索。是不是允许我把?在括号后面。

我该如何进行搜索?

提前致谢

已添加

为了说清楚我没有使用任何编程语言的RegEx。我正在使用具有搜索和替换功能的文本编辑器,该功能允许模式搜索。所以我想删除日期周围的方括号。但是不要改变我文件中的任何其他内容。

7 个答案:

答案 0 :(得分:2)

保持简单。没有必要使用正则表达式。如果您想要所有日期/时间部分,则使用字段和字段分隔符。这是一个awk表达式。只需打印出第一列(关闭方括号作为字段分隔符。)

$ cat file
[2010-01-15 06:18:10.203] [0x00001388] [SHDNT] Shutdown Count Down = 2/5
[2010-01-15 06:18:11.203] [0x00001388] [SHDNT] Shutdown Count Down = 3/5

$ awk -F"]" '{print $1"]"}' file
[2010-01-15 06:18:10.203]
[2010-01-15 06:18:11.203]

或者只使用空格作为分隔符打印出字段1和2

$ awk '{print $1,$2}' file
[2010-01-15 06:18:10.203]
[2010-01-15 06:18:11.203]

更新:要删除方括号,只需在字段1和2上使用gsub()sub()

$ awk '{gsub(/^\[/,"",$1);gsub(/\]$/,"",$2)}1' file
2010-01-15 06:18:10.203 [0x00001388] [SHDNT] Shutdown Count Down = 2/5
2010-01-15 06:18:11.203 [0x00001388] [SHDNT] Shutdown Count Down = 3/5

答案 1 :(得分:2)

以下正则表达式:

^\[([^\]]+)\]

将捕获字符串开头的日期加上方括号,并将之间的东西放在方括号中,组成一个可以自行提取的组。

请注意,文本编辑器的语法可能略有不同。以下是这种情况:

^ = beginning of line/string
\[, \] = literal [ and ] characters
() = signifies a group to capture
[^\]] = matches any character _except_ a close bracket
        (this keeps the match from being too greedy)
+ = one or more of the previous

编辑:这假设您的正则表达设施支持群组(大多数人都这样做)。解释组的最简单方法就是向您展示它们如何与一个这样的引擎一起工作。在Python解释器中:

>>> import re
>>> s = '[2010-01-15 06:18:10.203] [0x00001388] [SHDNT] ...'
>>> r = re.compile(r'^\[([^\]]+)\]')
>>> m = r.search(s)

这将创建一个正则表达式对象,并在字符串中搜索与其匹配的第一组文本。结果将在匹配对象中返回:

>>> m
<_sre.SRE_Match object at 0x1004d9558>

要获取匹配的整个文本集,Python约定是在匹配对象上调用group()

>>> m.group()
'[2010-01-15 06:18:10.203]'

并且为了得到括号中的东西,我传递了我想要的组的数量(在这种情况下,只有一组parens,所以只有一组):

>>> m.group(1)
'2010-01-15 06:18:10.203'

如果我执行替换而不是搜索,我使用sub函数。 Sub接受我要替换完整匹配的字符串,后跟输入字符串,如果找到匹配则返回执行替换的字符串:

>>> r.sub('spam spam spam', s)
'spam spam spam [0x00001388] [SHDNT] ...'

但是,替换字符串支持转义序列,该转义序列引用匹配捕获的组的特定值。组替换由\N表示,其中 N 是组的编号。因此:

>>> r.sub(r' \1 ', s)
' 2010-01-15 06:18:10.203  [0x00001388] [SHDNT] ...'

这就是你想要的。

答案 2 :(得分:1)

我不确定你需要在正则表达式中使用前瞻性或后瞻性断言:

 sarnold@haig:/tmp$ cat date.pl
 #!/usr/bin/perl -w

 while(<>) {
     /^(\[\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\])/;
     print "$1\n";
 }
 sarnold@haig:/tmp$ cat data
 [2010-01-15 06:18:10.203] [0x00001388] [SHDNT] Shutdown Count Down = 2/5
 [2010-01-15 06:18:11.203] [0x00001388] [SHDNT] Shutdown Count Down = 3/5
 sarnold@haig:/tmp$ ./date.pl data
 [2010-01-15 06:18:10.203]
 [2010-01-15 06:18:11.203]

我无法从您的说明中看出,如果您 想要约会[],或者想要他们。如果您不想使用方括号,请将它们移到parens之外:

     /^\[(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d)\]/;

sarnold@haig:/tmp$ ./date.pl data
2010-01-15 06:18:10.203
2010-01-15 06:18:11.203

请注意,我还将regexp锚定在行的开头,以防输出在其他地方的括号中包含日期时间事物。另外,与您的示例相比,我过度指定了日期时间。考虑一下偏执狂。如果您想用\d\d\d\d替换\d{4},可以使用{{1}},但在此示例中,我发现更长的形式更具可读性。

答案 3 :(得分:0)

我同意ghostdog你应该保持简单,但你也可以用正则表达式保持简单:

  1. ^匹配一行的开头。
  2. .匹配任何单个字符。
  3. *?将之前的事物与NON-GREEDILY进行零次或多次匹配,这意味着它不需要花费更多时间来完成其余的正则表达式匹配。
  4. 将它们放在一起,你会得到^.*?\],它从行的开头到它看到的第一个]匹配。

    编辑:刚刚看到你对ghostdog的回复,这澄清了问题。将整个日期与大括号相匹配仍然更容易。一旦你有了,只需用自己替换整个字符串,减去第一个和最后一个字符。我不知道你使用的语言是什么,但在Python中它会是这样的:

    new_string = re.sub(r'^.*?\]',original_string,lambda m:m.group()[1:-1])
    

答案 4 :(得分:0)

因为输入格式非常严格,所以采用非常简单的方法:

$ cut -c 2-24 <<EOF
[2010-01-15 06:18:10.203] [0x00001388] [SHDNT] Shutdown Count Down = 2/5
[2010-01-15 06:18:11.203] [0x00001388] [SHDNT] Shutdown Count Down = 3/5
EOF

2010-01-15 06:18:10.203
2010-01-15 06:18:11.203

答案 5 :(得分:0)

不完全确定你需要一个正则表达式。如果是找到第一个字符,或确定方括号内的文本。也许我误解了你的问题?

C#示例:

LINQ:

string[] firsts = myFile.ReadAllLines().Select(f=>f[0]);

循环使用foreach

string[] allLines = myFile.ReadAllLines();
foreach (string line in allLines)
{
    char firstChar= line[0];
    Console.WriteLine("First char: " + firstChar.ToString());

    if (firstChar = '[')
    {
       int closing = line.IndexOf(']');
       string textWithin = line.SubString(0, closingSquare-1);
       Console.WriteLine("Found this text within the square brackets: " + textWithin);
    }
}

答案 6 :(得分:0)

啊,谢谢你在其中一个答案中的其他评论。

在vim中,我可能会使用视觉选择工具:将光标放在第一个[上,键入^VG(以到达文件的末尾) ,然后x删除该列。然后使用第一个]字符^VG重复(但G会将光标放在错误的字符上 - 所以请使用l或右边-arrow-key移至]),然后键入x以删除列。

如果它在列中没有完美排列(也许.203可能是更少的字符,比如.2)那么我会这样做:

:%s/^\[//
:%s/\(\d\)] /\1 /

当然注意到第二个正则表达式更脆弱;它会删除每行上数字和空格之间的第一个]。对于转义(),非vim不会那么烦人。

当然,如果你没有使用vi-clone,希望这可以很好地翻译。 :)