Regex来匹配不同的单词和负号结束后的所有内容

本文关键字:结束 单词 Regex | 更新日期: 2023-09-27 17:55:06

我有几个不同的段线,我需要得到它的中间部分。幸运的是,这个模式只有一些变化,但我不能让它适用于所有的变化。

1 INT. HIGH SCHOOL - DAY 1
EXT. HOUSE - NIGHT
2A INT. HOSPITAL - NIGHT 2A
3. EXT. AIRPORT - DAY 3.
4B. INT. MALL - NIGHT 4B.

我想要实现的是拥有从INT或EXT开始的字符串直到最后一个单词,不包括数字/字母或点组合。我想要这个:

INT. HIGH SCHOOL - DAY 
EXT. HOUSE - NIGHT
INT. HOSPITAL - NIGHT
EXT. AIRPORT - DAY
INT. MALL - NIGHT   

在regex

中是否有一种干净的方法来做到这一点?

我得到的最好的是使用这个:

@"(?:INT|EXT:).*$")

不幸的是,它只返回一个从INT开始直到结尾的字符串,但不能与EXT一起工作,也不能去掉结尾的数字/字母或点。

Regex来匹配不同的单词和负号结束后的所有内容

你不需要使用Regex -一个有效的linq解决方案:

var str = "1 INT.HIGH SCHOOL -DAY 1";
var newStr = String.Join(" ",str.Split().Where(s => !s.Any(c => Char.IsDigit(c)))).Trim();
Console.WriteLine(newStr);  // INT.HIGH SCHOOL -DAY

你可以试试这个:

((?:INT|EXT).*?)'s*'S*$
  • (?:INT|EXT):匹配INTEXT
  • .*?:匹配所有
  • 's*'S*$:匹配该行的最后一个字符(但不包含在匹配部分中)
示例

https://regex101.com/r/zC8mG5/9

replace: ('d'w?'.? ?)(.*)'1
     to: '2

这个适合你吗?

这里有一个非正则表达式的方法,如预期的工作:

 string[] prefixes = { "INT", "EXT" };
 for (int i = 0; i < list.Count; i++)
 {
    string oldS = list[i].Trim();
    int indexOflastSpace = oldS.LastIndexOf(' ');
    int endIndex = oldS.Length - 1;
    if(indexOflastSpace >= 0)
    {
        string rest = oldS.Substring(indexOflastSpace).TrimStart();
        // starts the last token with a digit?
        if(char.IsDigit(rest[0]))
            endIndex = indexOflastSpace;
    }
    int start = 0;
    int indexOfAnyPrefix = prefixes
        .Select(p => oldS.IndexOf(p, StringComparison.InvariantCultureIgnoreCase))
        .Where(index => index >= 0)
        .DefaultIfEmpty(-1)
        .First();
    if(indexOfAnyPrefix > 0)
        start = indexOfAnyPrefix;
    string newS = oldS.Substring(start, endIndex - start);
    list[i] = newS;
}

这可以工作,并给出您需要的结果:

@".*((?:INT. |EXT. )[A-Za-z'. '-]+).*$"

用法如下:

var vMatch = Regex.Match("1 INT. HIGH SCHOOL - DAY 1", @".*((?:INT. |EXT. )[A-Za-z'. '-]+).*$");
var extracted = vMatch.Groups[1].Value.Trim();

extracted按要求包含INT. HIGH SCHOOL - DAY

使用Regex和Linq的替代方案(在线尝试):

string s = @"1 INT. HIGH SCHOOL - DAY 1
EXT. HOUSE - NIGHT
2A INT. HOSPITAL - NIGHT 2A
3. EXT. AIRPORT - DAY 3.
4B. INT. MALL - NIGHT 4B.";
const string startWithNum = @"^'d";
foreach (var line in s.Split(''r', ''n').Select(item => new List<string>(item.Split(' '))))
{
    if (Regex.IsMatch(line[0], startWithNum))
        line.RemoveAt(0);
    if (Regex.IsMatch(line[line.Count - 1], startWithNum))
        line.RemoveAt(line.Count - 1);
    Console.WriteLine(String.Join(" ", line));
}
输出:

INT. HIGH SCHOOL - DAY
EXT. HOUSE - NIGHT
INT. HOSPITAL - NIGHT
EXT. AIRPORT - DAY
INT. MALL - NIGHT

这就是我的方法。我喜欢使用IgnorePatternWhitespace选项来提高表达式的可读性。

我在一个块中显示数据,但如果您逐行处理它也可以工作。

var text = "1 INT. HIGH SCHOOL - DAY 1" + Environment.NewLine;
text += "EXT. HOUSE - NIGHT" + Environment.NewLine;
text += "INT. HOSPITAL - NIGHT 2A" + Environment.NewLine;
text += "3. EXT. AIRPORT - DAY 3." + Environment.NewLine;
text += "4B. INT. MALL - NIGHT 4B." + Environment.NewLine;
var options = RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace;
var regex = new Regex("^ .*? (?<slug> (?:INT|EXT)''. .*?) (?:''s+?''d.*?)? $", options );
var matches = regex.Matches( text );
foreach( Match m in matches ){
    Console.WriteLine( "|" + m.Groups["slug"].Value + "|" );
}

生产:

|INT. HIGH SCHOOL - DAY|
|EXT. HOUSE - NIGHT |
|INT. HOSPITAL - NIGHT|
|EXT. AIRPORT - DAY|
|INT. MALL - NIGHT|