Иногда возникает необходимость разбить строку на подстроки, чья длина не превышает заданную максимальную длину. При этом, если слово не умещается в текущей строке, то его необходимо целиком перенести на новую строку.
Т.е. нам надо симулировать поведение функции Word Wrap из приложения Notepad в Windows.
Есть два варианта решения этой задачи:
- Написать алгоритм
- Прикрутить регулярные выражения. И если учесть, что такая задача может возникнуть где угодно (т.е. как на клиенте, так и на сервере), а регулярные выражения поддерживаются практически всеми языками программирования, то этот вариант кажется наиболее предпочтительным.
Вот просто пример на C#, когда нам нужно разбить строку с длинным почтовым адресом longAddressString и представить результат в виде коллекции строк, чья длинна не превышает 40 символов.
List<string> adresses = (from Match m in Regex.Matches(longAddressString, @"(?:((?>.{1,40}(?:(?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|.{1,40})(?:\r?\n)?|(?:\r?\n|$))") where !String.IsNullOrWhiteSpace(m.Value) select m.Value ).ToList();
А ниже объяснение работы данного регулярного выражения от автора.
# MS-Windows "Notepad.exe Word Wrap" simulation
# ( N = 16 )
# ============================
# Find: @"(?:((?>.{1,16}(?:(?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|.{1,16})(?:\r?\n)?|(?:\r?\n|$))"
# Replace: @"$1\r\n"
# Flags: Global
# Note - Through trial and error discovery, it apparears Notepad accepts an extra whitespace
# (possibly in the N+1 position) to help alignment. This matters not because thier viewport hides it.
# There is no trimming of any whitespace, so the wrapped buffer could be reconstituted by inserting/detecting a
# wrap point code which is different than a linebreak.
# This regex works on un-wrapped source, but could probably be adjusted to produce/work on wrapped buffer text.
# To reconstitute the source all that is needed is to remove the wrap code which is probably just an extra "\r".
(?:
# -- Words/Characters
( # (1 start)
(?> # Atomic Group - Match words with valid breaks
.{1,16} # 1-N characters
# Followed by one of 4 prioritized, non-linebreak whitespace
(?: # break types:
(?<= [^\S\r\n] ) # 1. - Behind a non-linebreak whitespace
[^\S\r\n]? # ( optionally accept an extra non-linebreak whitespace )
| (?= \r? \n ) # 2. - Ahead a linebreak
| $ # 3. - EOS
| [^\S\r\n] # 4. - Accept an extra non-linebreak whitespace
)
) # End atomic group
|
.{1,16} # No valid word breaks, just break on the N'th character
) # (1 end)
(?: \r? \n )? # Optional linebreak after Words/Characters
|
# -- Or, Linebreak
(?: \r? \n | $ ) # Stand alone linebreak or at EOS
)