Regex, разделен на небуквено-цифрови знаци със специално третиране на думите с апострофи, съкращения

Опитвам се да разделя низ с помощта на Regex в C#. Искам да го разделя на базата на всички небуквено-цифрови знаци, но бих искал да третирам думите с апостроф като цяла дума, когато съдържа съкращение като: 'd, 's, 't.
Един пример трябва да изясни какво бих искал да постигна . Като се има предвид изречение като:

"Steve's dog is mine 'not yours' I know you'd like'it"

Бих искал да получа следните символи:

steve's, dog, is, mine, not, yours, i, know, you'd, like, it

В момента използвам:

Regex.Split(str.ToLower(), @"[^a-zA-Z0-9_']").Where(s => s != String.Empty).ToArray<string>();

Връща:

steve's , dog , is , mine , 'not , yours', i , know, you'd, like'it

person trave80    schedule 27.08.2017    source източник
comment
Какво ще кажете за the Hundred Years' War - или say: 'the Hundred Years' War of yours' !? ;).   -  person shA.t    schedule 27.08.2017
comment
.Select(s => s.Trim('\'')) след Where решава проблема?   -  person Alexander Petrov    schedule 27.08.2017


Отговори (3)


Ето решение на половин regex-половин-LINQ:

string s = "Steve's dog is mine 'not yours' I know you'd like'it";
string[] result = Regex.Matches(s, "\\w+('(s|d|t|ve|m))?")
    .Cast<Match>().Select(x => x.Value).ToArray();

Опитвам се да съпоставя всичко, което искате да получите, вместо разделителите, по които искате да разделите. И тогава просто Selectредих Values и ги превърнах всичките в масив.

person Sweeper    schedule 27.08.2017
comment
Вашият няма да хване: should've i'm - person linden2015; 27.08.2017
comment
Операторът каза, че са необходими само d s и t. @липа2015 - person Sweeper; 27.08.2017

\w+(?:'(?![aeiou])\w+)?

\w+         // 1 or more word chars
(?:         // optional uncaptured group
'           // apostrophe
(?![aeiou]) // look ahead and assert the character class doesn't match
\w+         // 1 or more word chars
)?          // end of optional group
  • Улов: should've, i'm, 'tis
  • Не хваща: rock 'n' roll

Демо

person linden2015    schedule 27.08.2017

Решението, за което мога да се сетя, е нещо подобно:

var txt = "Steve's dog is mine 'not yours' I know you'd like'it, the Hundred Years' War, I'm - they're - don't - o'clock - we've 'the Hundred Years' War of yours'";

// Finding valid `'`s and replace them temporarily to something like `_replaceMe_`
// Then replace net `'` to a blank space ` `
var osTxt = Regex.Replace(txt.ToLower(), 
    @"(?<=[^a-z]i)'(?=m[^a-z])|(?<=[a-z])'(?=([rv]e|[ds])[^a-z])|(?<=[a-z]n)'(?=t[^a-z])|(?<=[^a-z]o)'(?=(clock)?[^a-z])", 
    "_replaceMe_")
    .Replace("\'"," ");

// Now, extract words from sentence and replace `_replaceMe_` back to `'`
var words = Regex.Matches(osTxt, @"\w+")
    .OfType<Match>()
    .Select(c=> c.Value.Replace("_replaceMe_", "\'"))
    .ToList();

Но това няма да има ' от Years' в изречение като the Hundred Years' War.
Освен това има някои други валидна ситуация игнорираните ;).

person shA.t    schedule 27.08.2017