2012-06-20 6 views
5

У меня есть файл текстовых данных, который я, скорее всего, буду читать с readLines. Начальная часть каждой строки содержит много тарабарщины, за которыми следуют нужные мне данные. Таблетка и данные обычно разделяются тремя точками. Я хотел бы разбить строки после трех последних точек или заменить последние три точки маркером некоторого типа, говорящим R, чтобы лечить все слева от этих трех точек как один столбец.R: удаление последних трех точек из строки

Вот аналогичный пост на Stackoverflow, что будет найти последнюю точку:

R: Find the last dot in a string

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

В дополнение к gregexpr в сообщении выше Я попытался использовать gsub, но не могу решить, решение.

Вот Подайте пример данные и результат я надеюсь достичь:

aa = matrix(c(
'first string of junk... 0.2 0 1', 
'next string ........2 0 2', 
'%%%... ! 1959 ... 0 3 3', 
'year .. 2 .,. 7 6 5', 
'this_string is . not fine .•. 4 2 3'), 
nrow=5, byrow=TRUE, 
dimnames = list(NULL, c("C1"))) 

aa <- as.data.frame(aa, stringsAsFactors=F) 
aa 

# desired result 
#        C1 C2 C3 C4 
# 1  first string of junk 0.2 0 1 
# 2   next string ..... 2 0 2 
# 3    %%%... ! 1959  0 3 3 
# 4     year .. 2  7 6 5 
# 5 this_string is . not fine 4 2 3 

Я надеюсь, что этот вопрос не рассматривается слишком специфичен. Файл текстовых данных был создан с помощью шагов, описанных в моем сообщении со вчерашнего дня о чтении файла MSWord в R.

Некоторые из строк не содержат тарабарщины или трех точек, а только данные. Однако это может быть осложнением для последующей публикации.

Благодарим за любые советы.

+0

Вы можете выполнить поиск и заменить все запятые и большие точки на обычные точки в первую очередь? –

+0

Я не думаю, что могу заменить запятые точками, потому что данные содержат запятые в больших числах: 4,500. Я забыл упомянуть об этом в своем посте. Хотя, возможно, я мог бы заменить запятые точками, а затем удалить точки из данных после того, как я устранил тарабарщину. –

ответ

5

Это трюк, хотя и не особенно элегантный ...

options(stringsAsFactors = FALSE) 


# Search for three consecutive characters of your delimiters, then pull out 
# all of the characters after that 
# (in parentheses, represented in replace by \\1) 
nums <- as.vector(gsub(aa$C1, pattern = "^.*[.,•]{3}\\s*(.*)", replace = "\\1")) 

# Use strsplit to break the results apart at spaces and just get the numbers 
# Use unlist to conver that into a bare vector of numbers 
# Use matrix(, nrow = length(x)) to convert it back into a 
# matrix of appropriate length 
num.mat <- do.call(rbind, strsplit(nums, split = " ")) 


# Mash it back together with your original strings 
result <- as.data.frame(cbind(aa, num.mat)) 

# Give it informative names 
names(result) <- c("original.string", "num1", "num2", "num3") 
+0

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

+0

Похоже, что код присваивает номерам 4,2,3 (из последней строки) всем 5 строкам в наборе данных. –

+0

@MarkMiller Ах, извините - я работал с матрицей 'aa', а не как data.frame. Если вы хотите использовать data.frame, вы можете просто назначить 'nums' следующим образом:' as.vector (gsub (aa $ C1, pattern = "^. * [., •] {3} \\ s * (. *) ", replace =" \\ 1 "))' –

0

Реверс строка
Реверс шаблон, которую Вы ищете, если это необходимо, - это не в вашем случае
Обратный результат

[хайку-псевдокод]

a = 'first string of junk... 0.2 0 1' // string to search 
b = 'junk' // pattern to match 

ra = reverseString(a) // now equals '1 0 2.0 ...knuj fo gnirts tsrif' 
rb = reverseString (b) // now equals 'knuj' 

// run your regular expression search/replace - search in 'ra' for 'rb' 
// put the result in rResult 
// and then unreverse the result 
// apologies for not knowing the syntax for 'R' regex 

[/ haiku-pseudocode]

+1

Это хайку? Ох, неважно ... Я все еще не понимаю. – GSee

+0

См. Edit of haiku – KevinDTimm

2

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

# First, use a regex to eliminate the bad pattern. This regex 
# eliminates any three-character combination of periods, commas, 
# and big dots (•), so long as the combination is followed by 
# 0-2 spaces and then a digit. 
aa.sub <- as.matrix(
    apply(aa, 1, function (x) 
    gsub('[•.,]{3}(\\s{0,2}\\d)', '\\1', x, perl = TRUE))) 

# Second: it looks as though you want your data split into columns. 
# So this regex splits on spaces that are (a) preceded by a letter, 
# digit, or space, and (b) followed by a digit. The result is a 
# list, each element of which is a list containing the parts of 
# one of the strings in aa. 
aa.list <- apply(aa.sub, 1, function (x) 
    strsplit(x, '(?<=[\\w\\d\\s])\\s(?=\\d)', perl = TRUE)) 

# Remove the second element in aa. There is no space before the 
# first data column in this string. As a result, strsplit() split 
# it into three columns, not 4. That in turn throws off the code 
# below. 
aa.list <- aa.list[-2] 

# Make the data frame. 
aa.list <- lapply(aa.list, unlist) # convert list of lists to list of vectors 
aa.df <- data.frame(aa.list)  
aa.df <- data.frame(t(aa.df), row.names = NULL, stringsAsFactors = FALSE) 

Оставшийся Единственное, чтобы изменить регулярное выражение для strsplit() так что это может обрабатывать вторую строку в aa. Или, может быть, лучше просто обрабатывать такие случаи вручную.

+0

Если я добавлю пробел между последней точкой и 2 во второй строке, вы можете изменить строку aa.list на справиться? В моих реальных данных я думаю, что после последней точки всегда было пространство, и я просто не осознавал этого, когда создал «аа». Я также могу попытаться выяснить, как изменить aa.list. –

+0

Да, если вы добавите пробел между последней точкой и второй строкой, регулярное выражение на втором шаге может быть изменено для обработки этой строки. Это немного сложно, но выполнимо. Тем не менее, я думаю, что @MattParker имеет лучшую идею: начните с разделения каждой из ваших строк на «плохую» часть (первый столбец) и хорошо выполненную часть (столбцы данных). Затем примените регулярные выражения к первому столбцу. Затем присоединитесь к двум частям. Если вы сделаете это так, вы можете сохранить регулярное выражение в 'strsplit' довольно простым. В противном случае регулярное выражение будет более сложным. – user697473