i am new at Progress openedge! I would like to know how to split a user entered String with using procedure!
length of string could be max 2000 and every single Line contains max 35 Character.And spaces between Words must be also to considered.if a single line max > 35 then must begin with another line but not like this : ....hel
lo.........
it has to after 35.Line cutting off and spring next line but the spaces make me so confused and i cant find any Algorithm
For example:
myfield2 = "Many districts and landmarks in New York City are well known, and the city received a record 62.8 million tourists in 2017".
if index(myfield2,spacee) = 0 then do:
do while ii < length(myfield2) :
line = substring(myfield2,ii,35).
ii = ii + 35.
end.
end.
display line.
else if index(myfield2,spacee) <> 0 and length(myfield2) < 35 then do:
.......
sth like this ?
thank you!
You can find the space character left to your 35th character using R-INDEX
R-INDEX (myfield2, " ", ii) .
Another approach:
define variable t as character no-undo.
define variable x as character no-undo format "x(36)".
define variable i as integer no-undo.
define variable n as integer no-undo.
t = "Many districts and landmarks in New York City are well known, and the city received a record 62.8 million tourists in 2017".
n = num-entries( t, " " ).
do i = 1 to n:
if length( x + entry( i, t, " " )) < 35 then
do:
x = x + entry( i, t, " " ) + " ".
next.
end.
display x with frame a down.
down 1 with frame a.
x = entry( i, t, " " ) + " ".
end.
display x with frame a down.
or, if you prefer a variable with embedded newlines:
define variable t as character no-undo.
define variable x as character no-undo format "x(36)".
define variable i as integer no-undo.
define variable j as integer no-undo.
define variable n as integer no-undo.
t = "Many districts and landmarks in New York City are well known, and the city received a record 62.8 million tourists in 2017".
n = num-entries( t, " " ).
do i = 1 to n:
if j < 35 and
(j + length( entry( i, t, " " )) + 1) < 35 then
do:
x = x + entry( i, t, " " ) + " ".
j = j + length( entry( i, t, " " )) + 1.
next.
end.
j = length( entry( i, t, " " )) + 1.
x = x + "~n" + entry( i, t, " " ) + " ".
end.
display x view-as editor size 40 by 10.
Something like this:
DEFINE VARIABLE cInput AS CHARACTER NO-UNDO INITIAL
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et ~
dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet ~
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, ~
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, ~
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea ~
takimata sanctus est Lorem ipsum dolor sit amet.".
DEFINE VARIABLE cOutput AS CHARACTER NO-UNDO.
DEFINE VARIABLE iPos AS INTEGER NO-UNDO.
DEFINE VARIABLE iPrev AS INTEGER NO-UNDO INITIAL 1 .
DEFINE VARIABLE iLength AS INTEGER NO-UNDO.
ASSIGN iLength = LENGTH (cInput, "CHARACTER").
repeatLoop:
REPEAT:
iPos = R-INDEX (cInput, " ", iPrev + 35) .
IF iPos = 0 THEN
ASSIGN iPos = iLength .
ASSIGN cOutput = cOutput + TRIM (SUBSTRING (cInput, iPrev, iPos - iPrev, "CHARACTER")) + "|~n".
IF iPos + 35 >= iLength THEN DO:
ASSIGN cOutput = cOutput + TRIM (SUBSTRING (cInput, iPos, -1, "CHARACTER")) .
LEAVE repeatLoop.
END.
ASSIGN iPrev = iPos .
END.
MESSAGE cOutput
VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
Try something like this. Should be work for you. It breaks the text into a temp table. You can break text to any text length you desire, just by adjusting the second parameter from procedure call.
def temp-table tt-editor no-undo
field linha as integer
field conteudo as character format 'x(80)':U
index editor-id is primary unique
linha.
procedure pi-print-editor:
def input param c-editor as char no-undo.
def input param i-len as integer no-undo.
def var i-linha as integer no-undo.
def var i-aux as integer no-undo.
def var c-aux as char no-undo.
def var c-ret as char no-undo.
IF c-editor = ? or i-len = ? THEN
RETURN.
for each tt-editor:
delete tt-editor.
end.
assign c-ret = chr(255) + chr(255).
do while c-editor <> "":
if c-editor <> "" then do:
assign i-aux = index(c-editor, chr(10)).
IF i-aux = 0 THEN DO:
assign i-aux = index(c-editor, chr(13)).
END.
if i-aux > i-len or (i-aux = 0 and length(c-editor) > i-len) then
assign i-aux = r-index(c-editor, " ", i-len + 1).
if i-aux = 0 then
assign c-aux = substr(c-editor, 1, i-len)
c-editor = substr(c-editor, i-len + 1).
else
assign c-aux = substr(c-editor, 1, i-aux - 1)
c-editor = substr(c-editor, i-aux + 1).
if i-len = 0 then
assign entry(1, c-ret, chr(255)) = c-aux.
else do:
assign i-linha = i-linha + 1.
create tt-editor.
assign tt-editor.linha = i-linha
tt-editor.conteudo = c-aux.
end.
end.
if i-len = 0 then
return c-ret.
end.
return c-ret.
end procedure.
RUN pi-print-editor ('modtemLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirporinviduntutlaboreet.Commentsusedtoasforclarificationoro. i mean the text without spaces.',35).
FOR EACH tt-editor:
DISP tt-editor.conteudo FORMAT 'x(40)' LENGTH(conteudo) WITH WIDTH 333.
END.
Hope it helps.
Related
I have a shiny app in which you select one of 100 options from a couple of select inputs to show one of 100 Rmds/html pages.
Once you have chosen an option, an Rmd is rendered and displayed in the app but it is slow to render each time. Once that Rmd is loaded, you can choose another option to see a different Rmd
Since Rmd are more responsive than shiny apps, is there a way for me to recreate the same functionality (Choose an option, that links you to the correct Rmd, but you are still able to select a different option and go to that option's Rmd) but completely contained within an Rmd or family of Rmds?
Thank you
Does it help?
---
title: Test
output:
flexdashboard::flex_dashboard:
vertical_layout: scroll
runtime: shiny_prerendered
---
# Page 0
```{r context='render'}
npages <- 3
links <- paste0("#section-page-", 1:npages)
names(links) <- paste0("Page ", 1:npages)
onChange <- '
function(value){
const a = document.createElement("a");
document.body.append(a);
a.href = value;
a.click();
a.remove();
}
'
selectizeInput(
"sel",
"Select a page",
choices = as.list(links),
options = list(
onChange = I(onChange)
)
)
```
```{r echo=FALSE}
backlink <- function(){
tags$a("Back to selection", href = "#section-page-0")
}
```
# Page 1
blablabla...
```{r context="render"}
backlink()
```
# Page 2
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
```{r context="render"}
backlink()
```
# Page 3
```{r context='render'}
uiOutput("contentBox", inline = TRUE)
```
```{r context='server'}
content <- reactive({
x <- rnorm(1)
tags$span(x, id = 'myspan')
})
output$contentBox <- renderUI({
content()
})
```
```{r context="render"}
backlink()
```
EDIT
Here is the same flex dashboard but this one does not use Shiny (except the Shiny widgets, but no Shiny server). It uses the JavaScript library select2 because I like it (I find the native dropdown lists are not pretty).
---
title: "Navigating without Shiny"
output:
flexdashboard::flex_dashboard:
vertical_layout: scroll
pandoc_args:
header-includes: select2_css.html
include-after: select2_js.html
---
```{js}
$(document).ready(function() {
$("#sel").select2({
width: "resolve"
});
$("#sel").on("select2:select", function(e){
const a = document.createElement("a");
document.body.append(a);
a.href = e.params.data.id;
a.click();
a.remove();
});
});
```
```{r setup, include=FALSE}
library(flexdashboard)
library(htmltools)
```
# Page 0
```{r results='asis'}
npages <- 3
links <- paste0("#page-", 1:npages)
names(links) <- paste0("Page ", 1:npages)
shiny::selectInput(
"sel",
"Select a page",
choices = as.list(links),
selectize = FALSE,
width = "20%"
)
```
```{r echo=FALSE}
backlink <- function(){
tags$a("Back to selection", href = "#section-page-0")
}
```
# Page 1
blablabla...
```{r results='asis'}
backlink()
```
# Page 2
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
```{r results='asis'}
backlink()
```
# Page 3
```{r results='asis'}
backlink()
```
File select2_css.html:
<link rel="stylesheet" href="select2.min.css"></link>
File select2_js.html:
<script src="select2.min.js"></script>
Of course I downloaded the two select2.min files.
Edit by OP:
I was unable to get the selectInput to render in a static Rmd so I used crosstalk to the same effect
```{r}
sd <- SharedData$new(data.frame(n = names(links), l = links), group = 'grp', key = unname(links))
crosstalk::filter_select(id = 'selles',
label = 'select a page',
sharedData = sd,
group = ~names(links),
allLevels = F,
multiple = F)
```
```{js}
var ct_filter = new crosstalk.FilterHandle('grp');
// Get notified when this group's filter changes
ct_filter.on("change", function(e) {
// e.value gives the filter
const a = document.createElement("a");
document.body.append(a);
a.href = e.value;
a.click();
a.remove();
});
```
I would like to return a logical vector with TRUE values for all elements in which any element from another character vector is detected.
Example data:
lorem <- c("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
As an example, I would like to search the elements 'sit' and 'non'.
I tried
str_detect(lorem, c('sit', 'non'))
and
str_detect(lorem, c('non', 'sit'))
which showed me that the second argument is probably being recycled, so the call str_detect(lorem, c('sit', 'non')) actually occurs as follows:
c(str_detect(lorem[1], 'sit'), str_detect(lorem[2], 'non'), str_detect(lorem[3], 'sit'), str_detect(lorem[4], 'non'))
I eventually came up with the following solution:
multi_string_detect<-function(x,y){
temp<-sapply(y, function(z){str_detect(x, z)})
apply(temp, 1, any)
}
multi_string_detect(lorem, c('sit', 'non')
[1] TRUE FALSE FALSE TRUE
Is there a clean/simpler alternative to my multi_string_detect function?
Another option is to collapse the pattern into a single string with |
library(stringr)
str_detect(lorem, str_c(c('non', 'sit'), collapse = "|"))
#[1] TRUE FALSE FALSE TRUE
From the string
s <- "|tree| Lorem ipsum dolor sit amet, |house| consectetur adipiscing elit,
|street| sed do eiusmod tempor incididunt ut labore et |car| dolore magna aliqua."
I want to extract the text after the letters within the |-symbols.
My approach:
words <- list("tree","house","street","car")
for(word in words){
expression <- paste0("^.*\\|",word,"\\|\\s*(.+?)\\s*\\|.*$")
print(sub(expression, "\\1", s))
}
This works fine for all but the last wortd car. It instead returns the entire string s.
How can I modify the regex such that for the last element of words-list in prints out dolore magna aliqua..
\Edit: Previously the list with expressions was a,b,c,d. Solutions to this specific problem cannot be generalized very well.
Try this:
library(stringi)
s <- '|a| Lorem ipsum dolor sit amet, |b| consectetur adipiscing elit,
|c| sed do eiusmod tempor incididunt ut labore et |d| dolore magna aliqua.'
stri_split_regex(s, '\\|[:alpha:]\\|')
[[1]]
[1] "" " Lorem ipsum dolor sit amet, "
[3] " consectetur adipiscing elit, \n" " sed do eiusmod tempor incididunt ut labore et "
[5] " dolore magna aliqua."
You can try this pattern
library(stringr)
s <- "|tree| Lorem ipsum dolor sit amet, |house| consectetur adipiscing elit,
|street| sed do eiusmod tempor incididunt ut labore et |car| dolore magna aliqua."
str_extract_all(s, regex("(?<=\\|)\\w+(?=\\|)"))
#[1] "tree" "house" "street" "car"
(?<=\\|): Look behind, position following by |; \\|: is an escape for |
\\w: word characters
(?=\\|): Lookahead, position followed by |
I suggest extracting all the words with corresponding values using stringr::str_match_all:
s <- "|tree| Lorem ipsum dolor sit amet, |house| consectetur adipiscing elit,
|street| sed do eiusmod tempor incididunt ut labore et |car| dolore magna aliqua."
words1 <- list("tree","house","street","car")
library(stringr)
expression <- paste0("\\|(", paste(words1, collapse="|"),")\\|\\s*([^|]*)")
result <- str_match_all(s, expression)
lapply(result, function(x) x[,-1])
See the R demo
Output:
[[1]]
[,1] [,2]
[1,] "tree" "Lorem ipsum dolor sit amet, "
[2,] "house" "consectetur adipiscing elit, \n"
[3,] "street" "sed do eiusmod tempor incididunt ut labore et "
[4,] "car" "dolore magna aliqua."
The regex is
\|(tree|house|street|car)\|\s*([^|]*)
See the regex demo, details:
\| - a | char
(tree|house|street|car) - Group 1: one of the words
\| - a | char
\s* - 0 or more whitespace chars
([^|]*) - Group 2: any 0 or more chars other than |.
The situation is as follows: I have a query
SELECT
n.id_nota, n.titulo, n.contenido, n.fecha_creacion, n.fecha_modificacion,
gn.id_grupo_nota, gn.titulo AS titulo_gn, gn.descripcion,
dn.id_documento_nota, dn.id_nota AS id_nota_dn, dn.id_tipo_documento_nota AS id_tipo_documento_nota_dn, dn.contenido AS contenido_dn ,
tdn.id_tipo_documento_nota, tdn.nombre
FROM nota n
LEFT JOIN grupo_nota gn ON n.id_grupo_nota = gn.id_grupo_nota
LEFT JOIN documento_nota dn ON n.id_nota = dn.id_nota
LEFT JOIN tipo_documento_nota tdn ON tdn.id_tipo_documento_nota = dn.id_tipo_documento_nota
WHERE
n.id_usuario = 1
ORDER BY
n.fecha_modificacion ASC
LIMIT 5
which returns the following Map
[
{
id_nota: 1,
titulo: "Game Cube 5x5",
contenido: "Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
fecha_creacion: 2020-05-04T04:53:36.360993,
fecha_modificacion: 2020-05-04T04:53:36.361028,
id_documento_nota: 2,
id_nota_dn: 1,
id_tipo_documento_nota_dn: 1,
contenido_dn: "dart.png"
},
{
id_nota: 1,
titulo: Game Cube 5x5,
contenido: Lorem ipsum dolor sit amet, consectetur adipiscing elit...,
fecha_creacion: 2020-05-04T04:53:36.360993,
fecha_modificacion: 2020-05-04T04:53:36.361028,
id_documento_nota: 1,
id_nota_dn: 1,
id_tipo_documento_nota_dn: 1,
contenido_dn: "flutter-icon.png"
}
]
Which is fine, but I don't know how to map it so that it returns the following:
[
{
id_nota: 1,
titulo: "Game Cube 5x5",
contenido: "Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
fecha_creacion: 2020-05-04T04:53:36.360993,
fecha_modificacion: 2020-05-04T04:53:36.361028,
ls_documento_nota: [
{
id_documento_nota: 2,
id_nota_dn: 1,
id_tipo_documento_nota_dn: 1,
contenido_dn: "dart.png",
},
{
id_documento_nota: 1,
id_nota_dn: 1,
id_tipo_documento_nota_dn: 1,
contenido_dn: "flutter-icon.png",
}
]
}
]
I come from the Spring ecosystem where his ORM made it automatic (as if by magic). I need help with this pls.
Result Map in sqflite cannot contains subcollection so you will always get the row result as you get now. SQLite itself only return list or rows where each row contains a list of simple values. You will either need another solution on top of it or...simply manipulate the result (pure dart) to get to the format you want using some king of map converter.
So here's my string:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam elit lacus, dignissim quis laoreet non, cursus id eros. Etiam lacinia tortor vel purus eleifend accumsan. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum vestibulum nisl vitae volutpat.
I need to split it every 100 characters (full words only) until all the characters are used up.
So we'd end up with:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam elit lacus, dignissim quis laoreet non,
and
cursus id eros. Etiam lacinia tortor vel purus eleifend accumsan. Pellentesque habitant morbi tristique
and
senectus et netus et malesuada fames ac turpis egestas. Quisque bibendum vestibulum nisl vitae volutpat.
Any ideas on the best way to do that?
Since Daniel replied with actual code similar to my description, I'm gonna go with a different suggestion. I might be one character off with count. This code prints the start/end offsets and the substrings. What YOU need to do is modify this to save the strings in an array instead:
<%
Dim LoremIpsum
LoremIpsum = "Lorem ipsum dolor sit amet....."
Response.Write LoremIpsum & "<br>"
SplitWords LoremIpsum, 100
Function SplitWords(text, maxlen)
Dim c, i, j, l
l = Len(text)
i = 1
j = maxlen
Do While (j < l And Response.IsClientConnected)
c = Mid(text, j, 1)
Do While (c <> " " And j > i)
j = j - 1
c = Mid(text, j, 1)
Loop
Response.Write(i & "<br>")
Response.Write(j & "<br>")
s = Mid(text, i, j-i)
Response.Write(s & "<br>")
i = j
j = j + maxlen
Loop
End Function
%>
First you may want to split your string with the space character as a delimiter. Then start with an empty string, iterate over each word in the array, concatenate each word to the new string until the number of words exceeds 100:
str = "Lorem ipsum ...."
words = Split(str)
stringSection = ""
wordCounter = 0
FOR EACH word IN words
stringSection = stringSection & word
wordCounter = wordCounter + 1
IF wordCounter >= 100 THEN
Response.Write(stringSection & "<BR /><BR />")
wordCounter = 0
stringSection = ""
ELSE
stringSection = stringSection & " "
END IF
NEXT
Response.Write(stringSection & "<BR /><BR />")
Note that the last Response.Write is necessary to handle the last stringSection, even though it might have not exceeded the 100 words.
I needed to count the spaces as well as have it as a function...here is what I came up with...
Function wordSubstring(txtString,maxLen)
words = Split(txtString," ")
charCounter = 0
stringSection = ""
For Each word IN words
stringSection = stringSection & word
charCounter = len(stringSection)
if charCounter >= maxLen Then
wordSubstring=stringSection
exit For
else
stringSection = stringSection & " "
end If
Next
wordSubstring = stringSection
End Function