Страницы: 1
RSS
Поставить пробел между текстом и цифрами
 
Вечер добрый, уважаемые форумчане!

Подскажите, пожалуйста, возможно формулой отделить в ячейке текст от цифр и поставить между ними пробел?
Входные данные:
1A136902RN010
1A101402OT010
1A158802GEM20

На выходе должно получится так:
1 A 136902 RN 010
1 A 101402 OT 010
1 A 158802 GEM 20
Изменено: masik - 25.10.2018 19:48:51
 
Напишите почту, пошлю Печкина с пустым файлом для Вашего примера.
 
masik,  и сразу напишите, количество может варироваться только в последних двух группах?
Изменено: БМВ - 25.10.2018 19:22:05
По вопросам из тем форума, личку не читаю.
 
БМВ, да, количество может быть разным во всех группах, кол. групп также может быть в разном порядке и с разным кол. символов в нём.
Еще один пример:
115788DW5
115788GH5
1157SD5

На выходе так:
115788 DW 5
115788 GH 5
1157 SD 5
Изменено: masik - 25.10.2018 19:39:59
 
Доброе время суток
Цитата
masik написал:
возможно формулой
Формулисты молчат... Udf-функцией
Код
Public Function insertSpaces(ByVal intoText As String) As String
    Dim pReg As Object
    Set pReg = CreateObject("VBScript.RegExp")
    pReg.Global = True: pReg.Pattern = "(\d(?=\D)|\D(?=\d))"
    insertSpaces = pReg.Replace(intoText, "$1 ")
End Function
 
ещё вариант UDF
Код
Function bbb$(t$)
 With CreateObject("VBScript.RegExp"): .Global = True: .Pattern = "(\D)(\d)"
  bbb = .Replace(t, "$1 $2"): .Pattern = "(\d)(\D)": bbb = .Replace(bbb, "$1 $2")
 End With
End Function
Изменено: кузя1972 - 25.10.2018 20:40:30
 
Андрей VG,  Андрей, а чего говорить, пока Join не появится , такое  или с ограничениями то не просто , а без ограничений и вовсе не получить.
По вопросам из тем форума, личку не читаю.
 
Против регулярных особо не попрешь, но вот другой подход, основанный на строках, но без посимвольного склеивания
Код
Function a(x)
Dim i&, f$
  f = String(Len(x), "@")
  For i = 1 To Len(x) - 1
    If IsNumeric(Mid$(x, i, 1)) Xor IsNumeric(Mid$(x, i + 1, 1)) Then Mid(f, i) = "#"
  Next
  a = Format(x, Replace(f, "#", "@ "))
End Function
 
Андрей VG, кузя1972, БМВ, Казанский, большое Вам СПАСИБО!
 
из расчета на 4 пробела и отсутствия спецсимволов. массивная
=REPLACE(REPLACE(REPLACE(REPLACE(A1;
SMALL(IF((MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)>"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)<"9")+(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)<"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)>"9");ROW(A$2:INDEX(A:A;LEN(A1)));99);4);;" ");
SMALL(IF((MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)>"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)<"9")+(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)<"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)>"9");ROW(A$2:INDEX(A:A;LEN(A1)));99);3);;" ");
SMALL(IF((MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)>"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)<"9")+(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)<"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)>"9");ROW(A$2:INDEX(A:A;LEN(A1)));99);2);;" ");
SMALL(IF((MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)>"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)<"9")+(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)));1)<"9")*(MID(A1;ROW(A$2:INDEX(A:A;LEN(A1)))-1;1)>"9");ROW(A$2:INDEX(A:A;LEN(A1)));99);1);;" ")
По вопросам из тем форума, личку не читаю.
 
Здравствуйте, коллеги! Чуть-чуть оптимизированная "универсальная" UDF-функция (исходный вариант взят отсюда). С параметрами Андрея из #5  должна выдавать те же результаты:
Код
' UDF для замены текста LookIn с помощью регулярных выражений.
' PatternStr: шаблон; ReplaceWith: замещающая строка; ReplaceAll=True: менять все вхождения (False: только первое)
' MatchCase=True: учитывать регистр букв (False: нет); MultiLine: см. свойство Regexp.Multiline
Function RegExpReplace(ByVal LookIn, ByVal PatternStr, Optional ByVal ReplaceWith = "", _
    Optional ByVal ReplaceAll As Boolean = True, Optional ByVal MatchCase As Boolean = True, Optional ByVal MultiLine As Boolean = False)
    Static regEx As Object
    If regEx Is Nothing Then
      Set regEx = CreateObject("VBScript.RegExp")
    End If
    With regEx
        If .Global <> ReplaceAll Then .Global = ReplaceAll
        If .IgnoreCase <> Not MatchCase Then .IgnoreCase = Not MatchCase
        If .Pattern <> PatternStr Then .Pattern = PatternStr
        RegExpReplace = .Replace(LookIn, ReplaceWith)
    End With
End Function
Владимир
 
Цитата
Казанский написал:
основанный на строках
Тогда вариант по мотивам решения от Виталия (BedVit) годичной давности
Код
Public Function insertSpaces2(ByVal intoText As String) As String
    Dim bArr() As Byte, i As Long
    Dim bOut() As Byte, vOff As Long
    bArr = intoText
    bOut = String(CLng(2 * Len(intoText)), " ")
    vOff = 0
    bOut(0) = bArr(0): bOut(1) = bArr(1)
    For i = 2 To UBound(bArr) Step 2
        If bArr(i - 2) > 47 And bArr(i - 2) < 58 And bArr(i - 1) = 0 And (bArr(i) < 48 Or bArr(i) > 57 Or bArr(i + 1) <> 0) _
           Or bArr(i) > 47 And bArr(i) < 58 And bArr(i + 1) = 0 And (bArr(i - 2) < 48 Or bArr(i - 2) > 57 Or bArr(i - 1) <> 0) Then
           vOff = vOff + 2
        End If
        bOut(i + vOff) = bArr(i): bOut(i + vOff + 1) = bArr(i + 1)
    Next
    insertSpaces2 = RTrim$(bOut)
End Function

Цитата
БМВ написал:
из расчета на 4 пробела и отсутствия спецсимволов. массивная
Михаил, силён. Ещё немного и уподобишься тому не ленивому формулисту :)
Изменено: Андрей VG - 25.10.2018 22:54:40
 
Цитата
Андрей VG написал:
тому не ленивому формулисту
:-) Андрей, ну, как не трудно заметить, буквально Копи , пэст, лэст, пэст   и 4,3,2, 1 :-)

Убрал ограничение на спецсимволы. ну и 99 наверно хватит для длины

=TRIM(REPLACE(REPLACE(REPLACE(REPLACE(A1;
SMALL(IF(NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1)))*ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1))+ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1))*NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1)));ROW(A$2:INDEX(A:A;99));99);4);;" ");
SMALL(IF(NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1)))*ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1))+ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1))*NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1)));ROW(A$2:INDEX(A:A;99));99);3);;" ");
SMALL(IF(NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1)))*ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1))+ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1))*NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1)));ROW(A$2:INDEX(A:A;99));99);2);;" ");
SMALL(IF(NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1)))*ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1))+ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99));1))*NOT(ISNUMBER(--MID(A1;ROW(A$2:INDEX(A:A;99))-1;1)));ROW(A$2:INDEX(A:A;99));99);1);;" "))
Изменено: БМВ - 26.10.2018 07:39:59 (Убрал лишние пробелы в конце)
По вопросам из тем форума, личку не читаю.
 
Измерил производительность. #5 на старых конфигурациях быстрее, чем #12 на 10%, на новых - в два раза. #8 на длинных строках сходит с дистанции с сообщением о нехватке буфера.
Код
Sub test()
  Dim s As String, i As Long, t As Double, s2 As String
  s = "AA1B23AX789"
  For i = 1 To 20
    s = s & s
  Next i
  Debug.Print "Длина ", Len(s)
  t = Timer: s2 = insertSpaces(s): Debug.Print "RegEx", Timer - t: s2 = ""
  t = Timer: s2 = insertSpaces2(s): Debug.Print "Массив", Timer - t
End Sub
Владимир
 
Миша, грязь оставил - пробелы справа

А если так?
=СЖПРОБЕЛЫ(ЗАМЕНИТЬ(ЗАМЕНИТЬ(ЗАМЕНИТЬ(ЗАМЕНИТЬ(A4;
МАКС(ЕСЛИ(ЕОШ(-ПСТР(A4;СТРОКА($1:$13);1));СТРОКА($1:$13)))+1;;" ");
МАКС(ЕОШ(-ПСТР(A4;СТРОКА($2:$13);1))*ЕЧИСЛО(-ПСТР(A4;СТРОКА($1:$12);1))*СТРОКА($2:$13));;" ");
МИН(ЕСЛИ(ЕЧИСЛО(-ПСТР(A4;СТРОКА($2:$13);1))*ЕОШ(-ПСТР(A4;СТРОКА($1:$12);1));СТРОКА($1:$12)))+1;;" ");
МИН(ЕСЛИ(ЕОШ(-ПСТР(A4;СТРОКА($1:$13);1));СТРОКА($1:$13)));;" "))

Ограничения: начало и конец строки - число, не более 4-х пробелов

Подзреваю, могкут быть проблемы с 3 и 4 пробелами... На показанных данных ошибки нет, а проверять уже некогда
 
Цитата
vikttur написал:
Миша, грязь оставил - пробелы справа
да, точно, и даже не оставил, а сам насорил и забыл подстричь :-), но не думаю что это  стоит применять , это скорее ответ Андрею, почему молчат формулисты.
Изменено: БМВ - 26.10.2018 07:37:06
По вопросам из тем форума, личку не читаю.
 
Цитата
sokol92 написал:
Измерил производительность
Доброе утро, Владимир.
Большое спасибо за тесты.
 
Цитата
sokol92 написал:
Измерил производительность... #8 на длинных строках сходит с дистанции с сообщением о нехватке буфера.
В данной задаче строка длиной больше миллиона - это сферический конь в вакууме. ТС привел пример строк. ИМХО следует сравнивать скорость обработки большого количества таких строк.
В функции insertSpacesS я сделал объект RegExp статическим, чтобы он не создавался и ликвидировался при каждом вызове функции. Без этой оптимизации время работы функции больше на полтора порядка. Также убрал ненужный ByVal.
Функция а в 2 1/4 раза медленнее RegExp.
Функция insertSpaces2 неожиданно оказалась быстрее.
Функция а1 отличается  тем, что IsNumeric(Mid(...)) не вызывается 2 раза на каждый символ, "числовость" предыдущего символа хранится в булевой переменной. Скорость возросла почти в 1,5 раза.
В функции а2 тормозная конструкция IsNumeric(Mid(...)) заменена на перенос кода символа в переменную типа Integer с помощью GetMem2 и использование арифметических операторов сравнения. Эта функция работает немного быстрее RegExp на моей системе. С закомментированной строкой вместо предыдущей скорость та же.
В функции а3 заменил оператор Mid на GetMem2. Чуть быстрее, но уже несущественно.
В функции а4 реализовано то же, что в insertSpaces2, но с помощью GetMem2. Драматическое ускорение.
В функции а6 заменил посимвольное копирование на блочное копирование с помощью RtlMoveMemory. На этом наборе данных выигрыша нет.
Функция а7 - придумал алгоритм через байтовый массив и StrConv. Работает только с латинскими буквами. Выигрывает у всех функций, не использующих функции доступа к памяти, но немного проигрывает RegExp.
Цитата
insertSpaces   144,5557     экстраполировано
insertSpacesS  4,014893
insertSpaces2  7
a              9,062988
a1             6,358887
a2             3,672119
a3             3,625
a5             1,125
a6             1,108887
a7             4,75
Код для 32 бит.
Скрытый текст
Напоследок - результат этого же кода в VB6 cо всеми опциями оптимизации
Изменено: Казанский - 29.10.2018 11:46:20 (добавил а7 и картинку)
 
Здравствуйте, Алексей! Большое спасибо за интересное исследование!
Владимир
 
Небольшой тюнинг функции insertSpaces2 по рецептам Алексея из #18:
Код
Public Function insertSpaces2(intoText As String) As String
    Dim bArr() As Byte, bOut() As Byte, i As Long, vOff As Long, b As Boolean
    bArr = intoText: bOut = Space(2 * Len(intoText))
    bOut(0) = bArr(0): bOut(1) = bArr(1)
    b = bArr(0) > 47 And bArr(0) < 58 And bArr(1) = 0
    For i = 2 To UBound(bArr) Step 2
        If b Xor bArr(i) > 47 And bArr(i) < 58 And bArr(i + 1) = 0 Then b = Not b: vOff = vOff + 2
        bOut(i + vOff) = bArr(i): bOut(i + vOff + 1) = bArr(i + 1)
    Next
    insertSpaces2 = RTrim$(bOut)
End Function
существенно ее ускоряет. Результаты тестов из #18 на 32-разрядной трассе (Excel 2016):
Код
insertSpacesS  1,265625 
insertSpaces2  0,78125 
a              3,03125 
a1             2,09375 
a2             1,109375 
a3             1,078125 
a5             0,3125 
a6             0,34375 
a7             1,390625 
На "сферическом коне" (#14) результаты такие:
Код
Длина          11534336 
RegEx          0,828125 
Массив         0,6875 

Правда, тестирование в 23:50 c учетом того, что timer возвращает Single, не совсем надежно... :)  
Владимир
Страницы: 1
Наверх