Помогите пожалуйста. Началось все здесь Предыдущая тема. Мне было необходимо в файле (более 4 млн строк), заменить значения на в строках по определенным условиям (что-то вроде ВПР). Это удалось решить с помощью PQ, но оказалось что выгрузить потом данные ооочень проблематично из запроса, а на лист я их загрузить не могу (ограничение по строкам). В прошлой теме рекомендовали сделать это через VBA, но я так и не нашел ни чего и еще больше запутался. Помогите, пожалуйста, разобраться, может быть с кодом или с темой где можно почитать информацию по данному случаю. Буду очень признателен любой помощи.
Суть в следующем: есть файл файл на 4 млн. строк, 2 столбца. 1 стлобце цифровое значение, а вот во втором мне нужно заменить слова на другие значения. Пример строки второго столбца "товар1: машина, качество1: хорошее, цена1: 123, товар2:мотоцикл, качество2: отличное, цена2: 233, ..." Пример как должно получиться "товар1: a machine, качество1: good, цена1: 123, товар2:motorcycle, качество2: great, цена2: 233, товар3: scooter, качество3: bad, цена3: 123"
Привет, форумчане.
Помогите пожалуйста. Началось все здесь Предыдущая тема. Мне было необходимо в файле (более 4 млн строк), заменить значения на в строках по определенным условиям (что-то вроде ВПР). Это удалось решить с помощью PQ, но оказалось что выгрузить потом данные ооочень проблематично из запроса, а на лист я их загрузить не могу (ограничение по строкам). В прошлой теме рекомендовали сделать это через VBA, но я так и не нашел ни чего и еще больше запутался. Помогите, пожалуйста, разобраться, может быть с кодом или с темой где можно почитать информацию по данному случаю. Буду очень признателен любой помощи.
Суть в следующем: есть файл файл на 4 млн. строк, 2 столбца. 1 стлобце цифровое значение, а вот во втором мне нужно заменить слова на другие значения. Пример строки второго столбца "товар1: машина, качество1: хорошее, цена1: 123, товар2:мотоцикл, качество2: отличное, цена2: 233, ..." Пример как должно получиться "товар1: a machine, качество1: good, цена1: 123, товар2:motorcycle, качество2: great, цена2: 233, товар3: scooter, качество3: bad, цена3: 123"monstr_ork
На скорую руку сделал через словарь - см. вложение
И замена слов чувствительна к регистру
UPD: есть ошибка - в слове "мотоцик_иж" заменилось только "мотоцикл" - тут нужно думать какой подход применить, для вычленения составных слов Или тупо поменять местами в таблице подмены, позиции "мотоцикл_иж" и "мотоцикл"
На скорую руку сделал через словарь - см. вложение
И замена слов чувствительна к регистру
UPD: есть ошибка - в слове "мотоцик_иж" заменилось только "мотоцикл" - тут нужно думать какой подход применить, для вычленения составных слов Или тупо поменять местами в таблице подмены, позиции "мотоцикл_иж" и "мотоцикл"Fidgy
Fidgy, как я видел решения (но не знал как все это оформить): дробим сроку на отдельный фразы, ключом будет ":" и "," т.к. заменить нам нужно каждую вторую фразу, ее и искать в таблице значений. Тем самым решаем проблему дробных слов.
И осталась главная проблема, с помощью чего это можно обработать? Через эксель я просто так его не открою. Читал про то что VBA может работать построчно, но ни чего не понял
Fidgy, как я видел решения (но не знал как все это оформить): дробим сроку на отдельный фразы, ключом будет ":" и "," т.к. заменить нам нужно каждую вторую фразу, ее и искать в таблице значений. Тем самым решаем проблему дробных слов.
И осталась главная проблема, с помощью чего это можно обработать? Через эксель я просто так его не открою. Читал про то что VBA может работать построчно, но ни чего не понял monstr_ork
Сообщение отредактировал monstr_ork - Вторник, 02.07.2019, 17:00
monstr_ork, я только сложный способ знаю 1) взять строку текста 2) Через функцию InStr найти позицию ":", если не найдено то берём 0. И найти позицию символа ",", если не найдено, то берём длину строки 3) Зная позиции этих символов, вытащить текст через функцию Mid 4) Найти полученный текст в таблице подмены, убрав пробелы с помощью функции Trim 5) С помощью функции Replace заменить найденное слово на нужное, указав параметр Start = номер позиции символа ":" +1 6) Повторить пункты 2 - 6, до тех пор, пока находим текст, только для функции InStr указываем параметр Start = номер позиции символа "," +1 7) перейти к следующей строке, выполнить пункт 2 - 6
Но по моему легче отсортировать таблицу с подменой, чтобы составное слово стояло выше несоставного (пример с мотоциклом) и воспользоваться процедурой которую я дал выше
monstr_ork, я только сложный способ знаю 1) взять строку текста 2) Через функцию InStr найти позицию ":", если не найдено то берём 0. И найти позицию символа ",", если не найдено, то берём длину строки 3) Зная позиции этих символов, вытащить текст через функцию Mid 4) Найти полученный текст в таблице подмены, убрав пробелы с помощью функции Trim 5) С помощью функции Replace заменить найденное слово на нужное, указав параметр Start = номер позиции символа ":" +1 6) Повторить пункты 2 - 6, до тех пор, пока находим текст, только для функции InStr указываем параметр Start = номер позиции символа "," +1 7) перейти к следующей строке, выполнить пункт 2 - 6
Но по моему легче отсортировать таблицу с подменой, чтобы составное слово стояло выше несоставного (пример с мотоциклом) и воспользоваться процедурой которую я дал вышеFidgy
Сообщение отредактировал Fidgy - Вторник, 02.07.2019, 17:25
monstr_ork, название темы очень общее, придумайте более конкретно, отражающее суть задачи. Тем более, что в первом посте это почти сформулировано Исправлено
monstr_ork, название темы очень общее, придумайте более конкретно, отражающее суть задачи. Тем более, что в первом посте это почти сформулировано ИсправленоPelena
"Черт возьми, Холмс! Но как??!!" Ю-money 41001765434816
monstr_ork, аа, у вас текст в другом файле находится? Это уже совсем другой вопрос Я даже не уверен что Excel здесь подходит. Возможно как-то через Access этот фарш можно провернуть В любом случае тут я не помогу(
monstr_ork, аа, у вас текст в другом файле находится? Это уже совсем другой вопрос Я даже не уверен что Excel здесь подходит. Возможно как-то через Access этот фарш можно провернуть В любом случае тут я не помогу(Fidgy
Этот файл даже через текстовый редактор не открывается.
Возьмите другой текстовый редактор В целом читать строку, обрабатывать, писать в другой файл, читать следующую строку до EOF. Обработку можно и через SPLIT Делать через разделители указанные.
Этот файл даже через текстовый редактор не открывается.
Возьмите другой текстовый редактор В целом читать строку, обрабатывать, писать в другой файл, читать следующую строку до EOF. Обработку можно и через SPLIT Делать через разделители указанные.bmv98rus
Замечательный Временно просто медведь , процентов на 20.
да наверно не совсем, исходный наверно все ж не XLSX(m) раз там 4мульта строк. 4,5 ГБ гипотетически можно загрузить целиком и разбить на строки в массив и с ним уже возиться, но это если система x64 и памяти не 4ГБ. Делайте пример исходного файла, но так чтоб он был один в один с исходным, по формату данных.
да наверно не совсем, исходный наверно все ж не XLSX(m) раз там 4мульта строк. 4,5 ГБ гипотетически можно загрузить целиком и разбить на строки в массив и с ним уже возиться, но это если система x64 и памяти не 4ГБ. Делайте пример исходного файла, но так чтоб он был один в один с исходным, по формату данных.bmv98rus
Замечательный Временно просто медведь , процентов на 20.
Сообщение отредактировал bmv98rus - Вторник, 02.07.2019, 20:01
bmv98rus, исходник в CSV. Исходные данные такие и есть. В архиве 3 файл, 1 исходник и 2 таблицы, со значениями на которые нужно менять.
Видел статью, где применяли язык SQL для работы с файлами, может есть кто из форумчан, которые работали по такому принципу? Как я понял, при выполнении кода с использованием SQL команд, файл не открывается, а строчку можно запихать в массив. Может можно обработать его?
bmv98rus, исходник в CSV. Исходные данные такие и есть. В архиве 3 файл, 1 исходник и 2 таблицы, со значениями на которые нужно менять.
Видел статью, где применяли язык SQL для работы с файлами, может есть кто из форумчан, которые работали по такому принципу? Как я понял, при выполнении кода с использованием SQL команд, файл не открывается, а строчку можно запихать в массив. Может можно обработать его?monstr_ork
Уточнение, список замен переменный или это все? Вопрос к тому, что проще не искать что есть в категориях и менять а заменять если есть по списку.
Уточнение, список замен переменный или это все? Вопрос к тому, что проще не искать что есть в категориях и менять а заменять если есть по списку.bmv98rus
Замечательный Временно просто медведь , процентов на 20.
ну в общих чертах для работы с файлом и при условии что сможет загрузится, загрузка словаря и прочее это отдельно
[vba]
Код
Sub repinFile() Set objDict = CreateObject("Scripting.Dictionary") With objDict .Add "хорошее", "good" .Add "отличное", "great" .Add "плохое", "bad" .Add "диван", "sofa" .Add "кресло", "armchair" .Add "машина", "a machine" .Add "мотоцикл", "motorcycle" .Add "мотоцикл_иж", "motorcycle_eg" .Add "самокат", "scooter" End With
Set FSO = CreateObject("Scripting.FileSystemObject") Set File = FSO.GetFile("C:\Temp\File\test.csv") Set TextStream = File.OpenAsTextStream(1) strTxt = TextStream.ReadAll() TextStream.Close TextArr = Split(strTxt, vbCr) strTxt = Empty For i = 0 To UBound(TextArr) Items = Split(TextArr(i), ";") If UBound(Items) > 0 Then Items1 = Split(Items(1), ",") For j = 0 To UBound(Items1) Items2 = Split(Items1(j), ":") strValue = Trim(Items2(1)) If objDict.Exists(strValue) Then Items1(j) = Replace(Items1(j), strValue, objDict(strValue)) Next Items(1) = Join(Items1, ",") TextArr(i) = Join(Items, ";") End If Next strTxt = Join(TextArr, vbCr) Set TextStream = FSO.CreateTextFile("C:\Temp\File\test_out.csv") TextStream.Write (strTxt) TextStream.Close
End Sub
[/vba]
Результирующий фал в приложении.
Если в память не загрузить весь файл (под рукой сейчас Excel x32 и я сделал пример на 4 лимона строк, естественно не загрузил) , то иначе и медленнее будет из-за Cr в качетсве разделителя строк. посимвольно читать придется
[vba]
Код
Sub repinFileLbL() Set objDict = CreateObject("Scripting.Dictionary") With objDict .Add "хорошее", "good" .Add "отличное", "great" .Add "плохое", "bad" .Add "диван", "sofa" .Add "кресло", "armchair" .Add "машина", "a machine" .Add "мотоцикл", "motorcycle" .Add "мотоцикл_иж", "motorcycle_eg" .Add "самокат", "scooter" End With
Set fso = CreateObject("Scripting.FileSystemObject") Set File = fso.GetFile("C:\Temp\File\test.csv") Set SourceTextStream = File.OpenAsTextStream(1) 'Set SourceText = fso.OpenTextFile("C:\Temp\File\test.csv", 1) Set DistTextStream = fso.CreateTextFile("C:\Temp\File\test_out.csv")
strTxt = vbNullString
While Not SourceTextStream.AtEndOfStream c = SourceTextStream.Read(1) If c = vbCr Then
Items = Split(strTxt, ";") If UBound(Items) > 0 Then Items1 = Split(Items(1), ",") For j = 0 To UBound(Items1) Items2 = Split(Items1(j), ":") strValue = Trim(Items2(1)) If objDict.Exists(strValue) Then Items1(j) = Replace(Items1(j), strValue, objDict(strValue)) Next Items(1) = Join(Items1, ",") strTxt = Join(Items, ";") End If DistTextStream.Write (strTxt & vbCr) strTxt = vbNullString Else strTxt = strTxt & c End If Wend DistTextStream.Write (vbLf) SourceTextStream.Close DistTextStream.Close End Sub
[/vba]
Тестовый файл молотил 20мин :-) А вот первый вариант, запустил в режиме VBS и там 40сек длилась загрузка , при преобразовании в массив память скаканула к 3ГБ (файл тестовый 578MB) , Start: 15:29:48 Start Load file: 15:29:48 Start Split: 15:30:26 Start Process: 15:31:40 Start Write File: 15:35:04 Finish: 15:35:15 Rows processed: 4194305
Fidgy, я посомтрел что у Dас было, а зачем был нужен в вашем варианте словарь? При таком алгоритме просто перебор массива даст тот же эффект.
ну в общих чертах для работы с файлом и при условии что сможет загрузится, загрузка словаря и прочее это отдельно
[vba]
Код
Sub repinFile() Set objDict = CreateObject("Scripting.Dictionary") With objDict .Add "хорошее", "good" .Add "отличное", "great" .Add "плохое", "bad" .Add "диван", "sofa" .Add "кресло", "armchair" .Add "машина", "a machine" .Add "мотоцикл", "motorcycle" .Add "мотоцикл_иж", "motorcycle_eg" .Add "самокат", "scooter" End With
Set FSO = CreateObject("Scripting.FileSystemObject") Set File = FSO.GetFile("C:\Temp\File\test.csv") Set TextStream = File.OpenAsTextStream(1) strTxt = TextStream.ReadAll() TextStream.Close TextArr = Split(strTxt, vbCr) strTxt = Empty For i = 0 To UBound(TextArr) Items = Split(TextArr(i), ";") If UBound(Items) > 0 Then Items1 = Split(Items(1), ",") For j = 0 To UBound(Items1) Items2 = Split(Items1(j), ":") strValue = Trim(Items2(1)) If objDict.Exists(strValue) Then Items1(j) = Replace(Items1(j), strValue, objDict(strValue)) Next Items(1) = Join(Items1, ",") TextArr(i) = Join(Items, ";") End If Next strTxt = Join(TextArr, vbCr) Set TextStream = FSO.CreateTextFile("C:\Temp\File\test_out.csv") TextStream.Write (strTxt) TextStream.Close
End Sub
[/vba]
Результирующий фал в приложении.
Если в память не загрузить весь файл (под рукой сейчас Excel x32 и я сделал пример на 4 лимона строк, естественно не загрузил) , то иначе и медленнее будет из-за Cr в качетсве разделителя строк. посимвольно читать придется
[vba]
Код
Sub repinFileLbL() Set objDict = CreateObject("Scripting.Dictionary") With objDict .Add "хорошее", "good" .Add "отличное", "great" .Add "плохое", "bad" .Add "диван", "sofa" .Add "кресло", "armchair" .Add "машина", "a machine" .Add "мотоцикл", "motorcycle" .Add "мотоцикл_иж", "motorcycle_eg" .Add "самокат", "scooter" End With
Set fso = CreateObject("Scripting.FileSystemObject") Set File = fso.GetFile("C:\Temp\File\test.csv") Set SourceTextStream = File.OpenAsTextStream(1) 'Set SourceText = fso.OpenTextFile("C:\Temp\File\test.csv", 1) Set DistTextStream = fso.CreateTextFile("C:\Temp\File\test_out.csv")
strTxt = vbNullString
While Not SourceTextStream.AtEndOfStream c = SourceTextStream.Read(1) If c = vbCr Then
Items = Split(strTxt, ";") If UBound(Items) > 0 Then Items1 = Split(Items(1), ",") For j = 0 To UBound(Items1) Items2 = Split(Items1(j), ":") strValue = Trim(Items2(1)) If objDict.Exists(strValue) Then Items1(j) = Replace(Items1(j), strValue, objDict(strValue)) Next Items(1) = Join(Items1, ",") strTxt = Join(Items, ";") End If DistTextStream.Write (strTxt & vbCr) strTxt = vbNullString Else strTxt = strTxt & c End If Wend DistTextStream.Write (vbLf) SourceTextStream.Close DistTextStream.Close End Sub
[/vba]
Тестовый файл молотил 20мин :-) А вот первый вариант, запустил в режиме VBS и там 40сек длилась загрузка , при преобразовании в массив память скаканула к 3ГБ (файл тестовый 578MB) , Start: 15:29:48 Start Load file: 15:29:48 Start Split: 15:30:26 Start Process: 15:31:40 Start Write File: 15:35:04 Finish: 15:35:15 Rows processed: 4194305
Fidgy, я посомтрел что у Dас было, а зачем был нужен в вашем варианте словарь? При таком алгоритме просто перебор массива даст тот же эффект.bmv98rus
bmv98rus, можно вместо objDict использовать файл с уже известными данными. которые нужно заменить? По поводу открытия, notepad тоже его не смог открыть. я не могу открыть данный файл стандартными программами, поэтому смотрю в сторону sql запроса. Он вроде бы не открывается файл, а только создает подключение, потом каждую строку в массив и ее уже обрабатывать макросом.
[vba]
Код
Sub sql_test()
Dim CON As New ADODB.Connection Dim RS As New ADODB.Connection Dim varArr
но даже подключиться не удалось, ошибка в том, что драйвер не найден и источник данных.
bmv98rus, можно вместо objDict использовать файл с уже известными данными. которые нужно заменить? По поводу открытия, notepad тоже его не смог открыть. я не могу открыть данный файл стандартными программами, поэтому смотрю в сторону sql запроса. Он вроде бы не открывается файл, а только создает подключение, потом каждую строку в массив и ее уже обрабатывать макросом.
[vba]
Код
Sub sql_test()
Dim CON As New ADODB.Connection Dim RS As New ADODB.Connection Dim varArr
bmv98rus, да, не нужен словарь Я сначала думал выбирать слова из строки и через словарь получать их подмену - тогда это было бы быстрее, так-как количество слов для подмены может быть значительно больше Но потом решил что легче просто перебирать все варианты слов, а переделывать на массив уже было лень
bmv98rus, да, не нужен словарь Я сначала думал выбирать слова из строки и через словарь получать их подмену - тогда это было бы быстрее, так-как количество слов для подмены может быть значительно больше Но потом решил что легче просто перебирать все варианты слов, а переделывать на массив уже было леньFidgy
невозможно обработать файл не открывая его. Другое дело, что обработку можно вести по разному.
В целом сделать VBS на вход в качестве аргументов которому подавать три файла. Исходный и два с терминами для перевода - не проблема. но мне не очень интересно.
невозможно обработать файл не открывая его. Другое дело, что обработку можно вести по разному.
В целом сделать VBS на вход в качестве аргументов которому подавать три файла. Исходный и два с терминами для перевода - не проблема. но мне не очень интересно.bmv98rus
Замечательный Временно просто медведь , процентов на 20.
Привет, Михаил. Что-то долго на таком алгоритме. У меня ровно для 4000000 строк вышла 101 секунда.
[vba]
Код
Public Sub translateWords() Dim pDict As New Scripting.Dictionary Dim parts() As String, i As Long, fso As New Scripting.FileSystemObject, pStream As Scripting.TextStream, t As Single
t = Timer Set pStream = fso.OpenTextFile("C:\Path\Files\test4kk.csv", ForReading, False) fillDictFromFile pDict, "C:\Path\Files\table_1.csv" fillDictFromFile pDict, "C:\Path\Files\table_2.csv" parts = Split(pStream.ReadAll, vbCrLf) pStream.Close For i = 0 To UBound(parts) parts(i) = translate(parts(i), pDict) Next Set pStream = fso.OpenTextFile("C:\Path\Files\test4kk_en.csv", ForWriting, True) pStream.Write Join(parts, vbCrLf) pStream.Close MsgBox Timer - t End Sub
Private Function translate(ByVal thisLine As String, ByVal thisDict As Scripting.Dictionary) As String Dim mainParts() As String, parts() As String, i As Long, keyVal() As String, sVal As String, sKey As String, sMain As String mainParts = Split(thisLine, ";") sMain = Trim$(mainParts(0)) parts = Split(mainParts(1), ",") For i = 1 To UBound(parts) keyVal = Split(parts(i), ":") sKey = Trim$(keyVal(0)): sVal = Trim$(keyVal(1)) If thisDict.Exists(sVal) Then sVal = thisDict(sVal) parts(i) = sKey & ":" & sVal Next i translate = sMain & ";" & Join(parts, ",") End Function
Private Sub fillDictFromFile(ByVal thisDict As Scripting.Dictionary, ByVal FileName As String) Dim fIn As Integer, sLine As String, parts() As String fIn = FreeFile Open FileName For Input As #fIn Do Until EOF(fIn) Line Input #fIn, sLine parts = Split(sLine, ";") thisDict(Trim$(parts(0))) = Trim$(parts(1)) Loop Close #fIn End Sub
[/vba]
Результирующий файл прилагаю. P. S. Если использовать построчное чтение/запись pStream.ReadLine/WriteLine, то выходит 179 секунд. Диск SSD.
Привет, Михаил. Что-то долго на таком алгоритме. У меня ровно для 4000000 строк вышла 101 секунда.
[vba]
Код
Public Sub translateWords() Dim pDict As New Scripting.Dictionary Dim parts() As String, i As Long, fso As New Scripting.FileSystemObject, pStream As Scripting.TextStream, t As Single
t = Timer Set pStream = fso.OpenTextFile("C:\Path\Files\test4kk.csv", ForReading, False) fillDictFromFile pDict, "C:\Path\Files\table_1.csv" fillDictFromFile pDict, "C:\Path\Files\table_2.csv" parts = Split(pStream.ReadAll, vbCrLf) pStream.Close For i = 0 To UBound(parts) parts(i) = translate(parts(i), pDict) Next Set pStream = fso.OpenTextFile("C:\Path\Files\test4kk_en.csv", ForWriting, True) pStream.Write Join(parts, vbCrLf) pStream.Close MsgBox Timer - t End Sub
Private Function translate(ByVal thisLine As String, ByVal thisDict As Scripting.Dictionary) As String Dim mainParts() As String, parts() As String, i As Long, keyVal() As String, sVal As String, sKey As String, sMain As String mainParts = Split(thisLine, ";") sMain = Trim$(mainParts(0)) parts = Split(mainParts(1), ",") For i = 1 To UBound(parts) keyVal = Split(parts(i), ":") sKey = Trim$(keyVal(0)): sVal = Trim$(keyVal(1)) If thisDict.Exists(sVal) Then sVal = thisDict(sVal) parts(i) = sKey & ":" & sVal Next i translate = sMain & ";" & Join(parts, ",") End Function
Private Sub fillDictFromFile(ByVal thisDict As Scripting.Dictionary, ByVal FileName As String) Dim fIn As Integer, sLine As String, parts() As String fIn = FreeFile Open FileName For Input As #fIn Do Until EOF(fIn) Line Input #fIn, sLine parts = Split(sLine, ";") thisDict(Trim$(parts(0))) = Trim$(parts(1)) Loop Close #fIn End Sub
[/vba]
Результирующий файл прилагаю. P. S. Если использовать построчное чтение/запись pStream.ReadLine/WriteLine, то выходит 179 секунд. Диск SSD.anvg