2014-11-11 3 views
0

У меня есть файл в несколько сотен мегабайт, содержащих строки:Синтаксический большую строку в Рубине

str1 x1 x2\n 
str2 xx1 xx2\n 
str3 xxx1 xxx2\n 
str4 xxxx1 xxxx2\n 
str5 xxxxx1 xxxxx2 

где x1 и x2 некоторые цифры. Насколько велики цифры x(...x)1 и x(...x)2 есть, неизвестно.

В каждой строке есть "\n". У меня есть список строк str2 и str4.

Я хочу найти соответствующие номера для этих строк.

Что я делаю довольно проста (и, вероятно, не является эффективным производительность мудрым):

source_str = read_from_file() # source_str contains all file content of a few hundred Megabyte 
str_to_find = [str2, str4] 
res = [] 
str_to_find.each do |x| 
    index = source_str.index(x) 
    if index 
    a = source_str[index .. index + x.length] # a contains "str2" 

    #?? how do I "select" xx1 and xx2 ?? 


    # and finally... 
    # res << num1 
    # res << num2 
    end 
end 

Обратите внимание, что я не могу применить source_str.split("\n") из-за ошибки ArgumentError: invalid byte sequence in UTF-8 и я не могу исправить это путем изменения файла в любом случае. Файл не может быть изменен.

+1

Что такое 'read_from_file()'? Вы сразу же вырываете весь файл в память? Это вряд ли возможно. Вместо этого рассмотрите возможность использования 'foreach' и итерации по файлу по очереди. Это так же быстро и гораздо более масштабируемо. Нам нужны лучшие входные образцы. Дайте нам разумные примеры для 'str2' и' str4'. На какой ОС вы работаете? –

+0

read_from_file() - метод, который возвращает целое содержимое файла, сказано. –

+0

«[Почему повреждение файла плохо?] (Http://stackoverflow.com/q/25189262/128421) объясняет, почему вы не хотите читать весь файл в памяти. –

ответ

2

Если вы хотите найти строку в текстовом файле, который звучит так, как будто вы читаете, затем читайте файл по строкам.

Класс IO имеет метод foreach, который позволяет легко читать файл по очереди, что также позволяет легко находить строки, содержащие определенную строку, которую вы хотите найти.

Если вы имели ваш входной исходный файл сохранен как «foo.txt», вы можете прочитать его, используя что-то вроде:

str2 = 'some value' 
str4 = 'some other value' 
numbers = [] 
File.foreach('foo.txt') do |li| 
    numbers << li.split[2] if li[str2] || li[str2] 
end 

В конце цикла numbers должен содержать цифры, которые вы хотите.

Вы говорите, что получаете ошибку кодирования, но вы не даете нам никаких подсказок, каковы символы, вызывающие это. Без этой информации мы не можем помочь вам исправить эту проблему, кроме как сказать, что вам нужно сообщить Ruby, что такое кодировка файла. Вы можете сделать это, когда файл будет открыт; Вы должны правильно установить open_args в зависимости от того, какая кодировка должна быть. Скорее всего, это должно быть кодирование ISO-8859-1 или Win-1252, поскольку они очень распространены с машинами Windows.


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

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

Ruby's Regexp имеет инструменты, необходимые для выполнения этой работы, но для правильной работы требуется использование библиотеки Regexp :: Assemble Perl, поскольку Ruby не имеет ничего близкого к ней. См. «Is there an efficient way to perform hundreds of text substitutions in ruby?» для получения дополнительной информации.

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

+0

'Если вы хотите найти строку в текстовом файле, которая звучит так, как будто вы читаете, то читайте файл по строкам.' - почему это лучше? Мне нужно найти ** список ** значений, итерация по каждой строке не кажется разумной, потому что мне придется перебирать ** каждое ** значение снова и снова. –

+0

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

+0

Спасибо за метод «split», я не знал, что он не может принимать никаких аргументов. –

3

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

Попробуйте переформулировать проблему, поэтому вы можете обрабатывать большой входной файл как поток , поэтому вместо того, чтобы запрашивать каждую строку, которую вы хотите найти «существует ли она в моем файле?», Попробуйте попросить каждая строка в файле «содержит ли строку, которую я ищу?».

str_to_find = [str2, str4] 
numbers = [] 
File.foreach('foo.txt') do |li| 
    columns = li.split 
    numbers += columns[2] if str_to_find.include?(columns.shift) 
end 

Кроме того, перечитать @ ответ theTinMan в отношении кодирования файлов - то, что он предполагает, что вы можете быть в состоянии точно настроить чтение файла, чтобы избежать ошибок, не изменяя сам файл.

Если у вас есть очень большое количество элементов в str_to_find, я хотел бы предложить, что вы используете Set вместо с Array для лучшей производительности:

str_to_find = [str1, str2, ... str5000].to_set 
+0

'поэтому вместо того, чтобы запрашивать каждую строку, которую вы хотите найти,« существует ли она в моем файле? », Попробуйте запросить каждую строку в файле« содержит ли она строку, которую я ищу? ».' - это делает любая разница? раз b является тем же b раз a, не так ли? –

+0

Размер str_to_find довольно большой. –

+1

@MarioHonse - уверен, что это имеет значение - вам не нужно иметь весь 100 МБ текста в памяти ... Кроме того, найти подстроку внутри большой строки намного сложнее, чем сопоставление двух строк, чтобы увидеть, одинаковы ли они (не говоря уже о меньшем багги - 'str1' существует в' str12', хотя это может и не быть тем, что вы ищете). Насколько велика 'str_to_find'? есть ли у него тысячи записей? –

Смежные вопросы