Регулярное выражение, разделенное не буквенно-цифровыми символами, со специальной обработкой слов с сокращениями апострофов

Я пытаюсь разбить строку, используя Regex в С#. Я хочу разделить его на основе всех не буквенно-цифровых символов, но я хотел бы рассматривать слова с апострофами как целое слово, если оно содержит сокращение, такое как: '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)


Вот решение наполовину регулярного выражения наполовину 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обработал Value и превратил их все в массив.

person Sweeper    schedule 27.08.2017
comment
Ваш не поймает: should've i'm - person linden2015; 27.08.2017
comment
Оп сказал, что нужны только d s и t. @linden2015 - 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