Отдельная строка заголовка без пробелов в словах - PullRequest
31 голосов
/ 11 марта 2019

Я хочу найти и разделить слова в заголовке без пробелов.

До:

ThisIsAnExampleTitleHELLO-WORLD2019T.EST (Test) "Test" 'Test' [Test]

После:

Это пример названия HELLO-WORLD 2019 TEST (Тест) [Test] "Test" 'Test'


Я ищу правило регулярного выражения, которое может выполнять следующие действия.

Я подумал, что могу определить каждое слово, если оно начинается с заглавной буквы.

Нотакже сохраните все заглавные слова, чтобы не вставлять их в A L L U P P E R C A S E.

Дополнительные правила:

  • Пробел, если он касается числа: Hello2019World Hello 2019 World
  • Игнорировать интервальные инициалы, содержащие точки, дефисы или подчеркивания T.E.S.T.
  • Игнорировать интервалы между скобками, скобками или кавычками [Test] (Test) "Test" 'Test'
  • Сохранить дефисы Hello-World

C #

https://rextester.com/GAZJS38767

// Title without spaces
string title = "ThisIsAnExampleTitleHELLO-WORLD2019T.E.S.T.(Test)[Test]\"Test\"'Test'";

// Detect where to space words
string[] split =  Regex.Split(title, "(?<!^)(?=(?<![.\\-'\"([{])[A-Z][\\d+]?)");

// Trim each word of extra spaces before joining
split = (from e in split
         select e.Trim()).ToArray();

// Join into new title
string newtitle = string.Join(" ", split);

// Display
Console.WriteLine(newtitle);

Регулярное выражение

я хавиПроблемы с пробелами перед числами, скобками, скобками и кавычками.

https://regex101.com/r/9IIYGX/1

(?<!^)(?=(?<![.\-'"([{])(?<![A-Z])[A-Z][\d+?]?)

(?<!^)          // Negative look behind

(?=             // Positive look ahead

(?<![.\-'"([{]) // Ignore if starts with punctuation
(?<![A-Z])      // Ignore if starts with double Uppercase letter
[A-Z]           // Space after each Uppercase letter
[\d+]?          // Space after number

)

Решение

Спасибо за все ваши совместные усилия вответы.Вот пример Regex.Я применяю это к именам файлов и исключаю специальные символы \/:*?"<>|.

https://rextester.com/FYEVE73725

https://regex101.com/r/xi8L4z/1

Ответы [ 4 ]

18 голосов
/ 11 марта 2019

Вот регулярное выражение, которое, кажется, работает хорошо, по крайней мере, для вашего примера ввода:

(?<=[a-z])(?=[A-Z])|(?<=[0-9])(?=[A-Za-z])|(?<=[A-Za-z])(?=[0-9])|(?<=\W)(?=\W)

Этот паттен говорит сделать раскол на границе одного из следующих условий:

  • то, что предшествует строчными буквами, а то, что предшествует прописными (или наоборот)
  • что предшествует цифре, а что следует букве (или наоборот)
  • что предшествует, а что следует, это не слово (например, цитата, скобка и т. д.)


string title = "ThisIsAnExampleTitleHELLO-WORLD2019T.E.S.T.(Test)[Test]\"Test\"'Test'";
string[] split =  Regex.Split(title, "(?<=[a-z])(?=[A-Z])|(?<=[0-9])(?=[A-Za-z])|(?<=[A-Za-z])(?=[0-9])|(?<=\\W)(?=\\W)"); 
split = (from e in split select e.Trim()).ToArray();
string newtitle = string.Join(" ", split);

This Is An Example Title HELLO-WORLD 2019 T.E.S.T. (Test) [Test] "Test" 'Test'

Примечание: вы также можете добавить это утверждение в чередование регулярных выражений:

(?<=\W)(?=\w)|(?<=\w)(?=\W)

Нам здесь сошло с рук, потому что этого граничного условия никогда не было. Но вам может понадобиться это с другими входами.

9 голосов
/ 11 марта 2019

Стремясь к простоте, а не к огромному регулярному выражению, я бы порекомендовал этот код с небольшими простыми шаблонами (комментарии с пояснениями находятся в коде):

string str = "ThisIsAnExampleTitleHELLO-WORLD2019T.E.S.T.(Test)\"Test\"'Test'[Test]";
// insert space when there is small letter followed by upercase letter
str = Regex.Replace(str, "(?<=[a-z])(?=[A-Z])", " ");
// insert space whenever there's digit followed by a ltter
str = Regex.Replace(str, @"(?<=\d)(?=[A-Za-z])", " ");
// insert space when there's letter followed by digit
str = Regex.Replace(str, @"(?<=[A-Za-z])(?=\d)", " ");
// insert space when there's one of characters ("'[ followed by letter or digit
str = Regex.Replace(str, @"(?=[(\[""'][a-zA-Z0-9])", " ");
// insert space when what preceeds is on of characters ])"'
str = Regex.Replace(str, @"(?<=[)\]""'])", " ");
8 голосов
/ 11 марта 2019

Первые несколько частей похожи на @ revo answer : (?<!^|[A-Z\p{P}])[A-Z]|(?<=\p{P})\p{P}, дополнительно я добавляю следующее регулярное выражение в пробел между числом и буквой: (?<=[a-z])(?=\d)|(?<=\d)(?=[a-z])|(?<=[A-Z])(?=\d)|(?<=\d)(?=[A-Z]) и для обнаружения OTPIsADevice затем замените на lookahead и lookbehind, чтобы найти строчные буквы с строчными: (((?<!^)[A-Z](?=[a-z]))|((?<=[a-z])[A-Z]))

Обратите внимание, что | - это или оператор, который разрешил выполнение всех регулярных выражений.

Регулярное выражение: (?<!^|[A-Z\p{P}])[A-Z]|(?<=\p{P})\p{P}|(?<=[a-z])(?=\d)|(?<=\d)(?=[a-z])|(?<=[A-Z])(?=\d)|(?<=\d)(?=[A-Z])|(((?<!^)[A-Z](?=[a-z]))|((?<=[a-z])[A-Z]))

Демо

Обновление

Немного импровизировано:

От: (?<!^|[A-Z\p{P}])[A-Z]|(?<=\p{P})\p{P}|(?<=[a-z])(?=\d)|(?<=\d)(?=[a-z])|(?<=[A-Z])(?=\d)|(?<=\d)(?=[A-Z])

в: (?<!^|[A-Z\p{P}])[A-Z]|(?<=\p{P})\p{P}|(?<=\p{L})\d, которые делают то же самое.

(((?<!^)(?<!\p{P})[A-Z](?=[a-z]))|((?<=[a-z])[A-Z]))|(?<!^)(?=[[({&])|(?<=[)\]}!&}]) импровизированный из OP комментарий , который добавляет исключение к некоторой пунктуации: (((?<!^)(?<!['([{])[A-Z](?=[a-z]))|((?<=[a-z])[A-Z]))|(?<!^)(?=[[({&])|(?<=[)\\]}!&}])

Финальное регулярное выражение: (?<!^|[A-Z\p{P}])[A-Z]|(?<=\p{P})\p{P}|(?<=\p{L})\d|(((?<!^)(?<!\p{P})[A-Z](?=[a-z]))|((?<=[a-z])[A-Z]))|(?<!^)(?=[[({&])|(?<=[)\]}!&}])

Демо

7 голосов
/ 11 марта 2019

Вы можете уменьшить требования к сокращению шагов регулярного выражения, используя другую их интерпретацию. Например, первое требование будет таким же, как сказать: сохранить заглавные буквы, если им не предшествуют знаки препинания или заглавные буквы.

Следующее регулярное выражение работает практически для всех упомянутых требований и может быть расширено для включения или исключения других ситуаций:

(?<!^|[A-Z\p{P}])[A-Z]|(?<=\p{P})\p{P}

Вы должны использовать метод Replace() и использовать $0 в качестве строки подстановки.

Смотрите живое демо здесь

.NET (см. в действии ):

string input = @"ThisIsAnExample.TitleHELLO-WORLD2019T.E.S.T.(Test)""Test""'Test'[Test]";
Regex regex = new Regex(@"(?<!^|[A-Z\p{P}])[A-Z]|(?<=\p{P})\p{P}", RegexOptions.Multiline);
Console.WriteLine(regex.Replace(input, @" $0"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...