Copying string failure in Fortran - string

I would like to have a procedure which makes a local copy b of input character a (of not assumed length) into an allocatable array of characters. I do have the following code
program test_copystr
character(len=6) :: str
str = 'abc'
call copystr(str)
contains
subroutine copystr(a)
character(len=*), intent(in) :: a
!> Local variables
integer :: i
character, allocatable :: b(:)
allocate(b(len_trim(a)))
do i=1, len_trim(a)
b(i) = a(i:i)
end do
print *, b
b(1:len_trim(a)) = a(1:len_trim(a))
print *, b
end subroutine copystr
end program test_copystr
where I'm trying to assign a to b in two different ways. The result is
abc
aaa
I thought that both assignments should yield the same output. Can anyone explain me that difference? (To compile this code I'm using gfortran 5.2.0 compiler.)

As you know b is an array of characters while a is a scalar; when the subroutine is called it is a 6-character string. These are different things. The statement
b(1:len_trim(a)) = a(1:len_trim(a))
specifies the array section b(1:3) on the lhs, that is all 3 elements of b, and the substring a(1:3) on the rhs. Now, when assigning a substring of length 3 to a single character such as any element of b Fortran assigns only the first character of the string.
In this case every element of b is set to the first character of a. It is as if the compiler generates the 3 statements
b(1) = 'abc'
b(2) = 'abc'
b(3) = 'abc'
to implement the array assignment. This is what Fortran's array syntax does with an array on the lhs and a scalar (expression) on the rhs, it broadcasts the scalar to each element of the array.
The first method you use, looping across the elements of b and the characters of a is the regular way make an array of characters equivalent to a string. But you could try transfer -- see my answer to this question Removing whitespace in string

Related

trouble with tripling letters [duplicate]

How can I iterate over a string in Python (get each character from the string, one at a time, each time through a loop)?
As Johannes pointed out,
for c in "string":
#do something with c
You can iterate pretty much anything in python using the for loop construct,
for example, open("file.txt") returns a file object (and opens the file), iterating over it iterates over lines in that file
with open(filename) as f:
for line in f:
# do something with line
If that seems like magic, well it kinda is, but the idea behind it is really simple.
There's a simple iterator protocol that can be applied to any kind of object to make the for loop work on it.
Simply implement an iterator that defines a next() method, and implement an __iter__ method on a class to make it iterable. (the __iter__ of course, should return an iterator object, that is, an object that defines next())
See official documentation
If you need access to the index as you iterate through the string, use enumerate():
>>> for i, c in enumerate('test'):
... print i, c
...
0 t
1 e
2 s
3 t
Even easier:
for c in "test":
print c
Just to make a more comprehensive answer, the C way of iterating over a string can apply in Python, if you really wanna force a square peg into a round hole.
i = 0
while i < len(str):
print str[i]
i += 1
But then again, why do that when strings are inherently iterable?
for i in str:
print i
Well you can also do something interesting like this and do your job by using for loop
#suppose you have variable name
name = "Mr.Suryaa"
for index in range ( len ( name ) ):
print ( name[index] ) #just like c and c++
Answer is
M r . S u r y a a
However since range() create a list of the values which is sequence thus you can directly use the name
for e in name:
print(e)
This also produces the same result and also looks better and works with any sequence like list, tuple, and dictionary.
We have used tow Built in Functions ( BIFs in Python Community )
1) range() - range() BIF is used to create indexes
Example
for i in range ( 5 ) :
can produce 0 , 1 , 2 , 3 , 4
2) len() - len() BIF is used to find out the length of given string
If you would like to use a more functional approach to iterating over a string (perhaps to transform it somehow), you can split the string into characters, apply a function to each one, then join the resulting list of characters back into a string.
A string is inherently a list of characters, hence 'map' will iterate over the string - as second argument - applying the function - the first argument - to each one.
For example, here I use a simple lambda approach since all I want to do is a trivial modification to the character: here, to increment each character value:
>>> ''.join(map(lambda x: chr(ord(x)+1), "HAL"))
'IBM'
or more generally:
>>> ''.join(map(my_function, my_string))
where my_function takes a char value and returns a char value.
Several answers here use range. xrange is generally better as it returns a generator, rather than a fully-instantiated list. Where memory and or iterables of widely-varying lengths can be an issue, xrange is superior.
You can also do the following:
txt = "Hello World!"
print (*txt, sep='\n')
This does not use loops but internally print statement takes care of it.
* unpacks the string into a list and sends it to the print statement
sep='\n' will ensure that the next char is printed on a new line
The output will be:
H
e
l
l
o
W
o
r
l
d
!
If you do need a loop statement, then as others have mentioned, you can use a for loop like this:
for x in txt: print (x)
If you ever run in a situation where you need to get the next char of the word using __next__(), remember to create a string_iterator and iterate over it and not the original string (it does not have the __next__() method)
In this example, when I find a char = [ I keep looking into the next word while I don't find ], so I need to use __next__
here a for loop over the string wouldn't help
myString = "'string' 4 '['RP0', 'LC0']' '[3, 4]' '[3, '4']'"
processedInput = ""
word_iterator = myString.__iter__()
for idx, char in enumerate(word_iterator):
if char == "'":
continue
processedInput+=char
if char == '[':
next_char=word_iterator.__next__()
while(next_char != "]"):
processedInput+=next_char
next_char=word_iterator.__next__()
else:
processedInput+=next_char

Convert a string into an integer of its ascii values

I am trying to write a function that takes a string txt and returns an int of that string's character's ascii numbers. It also takes a second argument, n, that is an int that specified the number of digits that each character should translate to. The default value of n is 3. n is always > 3 and the string input is always non-empty.
Example outputs:
string_to_number('fff')
102102102
string_to_number('ABBA', n = 4)
65006600660065
My current strategy is to split txt into its characters by converting it into a list. Then, I convert the characters into their ord values and append this to a new list. I then try to combine the elements in this new list into a number (e.g. I would go from ['102', '102', '102'] to ['102102102']. Then I try to convert the first element of this list (aka the only element), into an integer. My current code looks like this:
def string_to_number(txt, n=3):
characters = list(txt)
ord_values = []
for character in characters:
ord_values.append(ord(character))
joined_ord_values = ''.join(ord_values)
final_number = int(joined_ord_values[0])
return final_number
The issue is that I get a Type Error. I can write code that successfully returns the integer of a single-character string, however when it comes to ones that contain more than one character, I can't because of this type error. Is there any way of fixing this. Thank you, and apologies if this is quite long.
Try this:
def string_to_number(text, n=3):
return int(''.join('{:0>{}}'.format(ord(c), n) for c in text))
print(string_to_number('fff'))
print(string_to_number('ABBA', n=4))
Output:
102102102
65006600660065
Edit: without list comprehension, as OP asked in the comment
def string_to_number(text, n=3):
l = []
for c in text:
l.append('{:0>{}}'.format(ord(c), n))
return int(''.join(l))
Useful link(s):
string formatting in python: contains pretty much everything you need to know about string formatting in python
The join method expects an array of strings, so you'll need to convert your ASCII codes into strings. This almost gets it done:
ord_values.append(str(ord(character)))
except that it doesn't respect your number-of-digits requirement.

Unable to compile function which returns parts of a string

I want to use following function in my code. I want it to take given string, cut all leading zeros and return a string without the leading zeros. For example I give it '00023' and it shall return '23___' (_ is space)
I have this function in my code:
function cut_zeros(string)
implicit none
character(5) :: cut_zeros, string
integer:: string_limit, i
string_limit = 5
do i= 1, string_limit
if (string(i)/='0') then
cut_zeros = string(i : string_limit)
exit
endif
enddo
end function cut_zeros
I really don't know what problem the compiler has. It gives this information:
cut_zeros = string(i : string_limit)
1
Error: Syntax error in argument list at (1)
I also have another question? Is it possible to make the function assumed length? So that I can pass a string of any length to it? As far as I understand it is not possible, because the return value of a function cannot be assumed length, right?
The error message is actually misleading. The error happens one line above: to compare the i-th character, you need to use string(i:i). If you change that line to
if (string(i:i)/='0') then
the code works as expected.
For the second part of your question, you can use assumed length strings! You can simply set the length of the return value to the length of the input string:
function cut_zeros(string)
implicit none
character(*) :: string
character(len=len(string)) :: cut_zeros
integer:: string_limit, i
string_limit = len(string)
do i= 1, string_limit
if (string(i:i)/='0') then
cut_zeros = string(i : string_limit)
exit
endif
enddo
end function cut_zeros
Here, the length of the return string is chosen that if no zeroes are removed, it still has a valid length. Note that you will require an interface to handle assumed length dummy arguments.
To crop the output string to the exact length required you would need allocatable strings which is not fully supported by all compilers:
function cut_zeros(string)
implicit none
character(*) :: string
character(len=:),allocatable :: cut_zeros
integer:: string_limit, i
string_limit = len(string)
do i= 1, string_limit
if (string(i:i)/='0') then
allocate( character(len=string_limit-i+1) :: cut_zeros )
cut_zeros = string(i : string_limit)
exit
endif
enddo
end function cut_zeros
Or you could use Fortran's existing capabilities
CHARACTER(6) :: src = '002305'
CHARACTER(LEN(src)) :: dest
...
dest = src(SCAN(src,'123456789'):)
! now dest is '2305__'
This only works if the first non-0 character is another digit, if you have other characters to worry about extend the set used in the 2nd argument to SCAN.
The syntax for a substring reference requires the separating colon, i.e. you want string(i:i). If you don't have that colon, the compiler considers that syntax to be a function reference (it knows it isn't an array reference, because you didn't declare string as an array).
You don't want an assumed length function. Such a thing exists, but they are an anachronism that is best forgotten. What you may want is an automatic length function, where the length of the function result depends on the input.
FUNCTION cut_zeros(string)
CHARACTER(*), INTENT(IN) :: string
! The length of the function result is the same as the length
! of the argument.
CHARACTER(LEN(string)) :: cut_zeros
A function with an automatic result requires an explicit interface in any scope where it is referenced. Best off putting it in a module, and USE'ing the module.

Lua: Substitute list of characters in string

Is it possible to substitute characters according to a list in Lua, like tr in Perl? For example, I would like to substitute A to B and B to A (e.g. AABBCC becomes BBAACC).
In Perl, the solution would be $str ~= tr/AB/BA/. Is there any native way of doing this in Lua? If not, I think the best solution would be iterating through the entire string, since separate substitutions need to use a special symbol to distinguish characters that were already substituted and characters that weren't.
Edit: my goal was to calculate the reverse complement of a DNA string, as described here.
string.gsub can take a table as the third argument. The table is queried for each match, using the first capture as the key, and the associated value is used as the replacement string. If the value is nil, the match is not changed.
So you can build a helper table like this:
local s = "AABBCC"
local t = {A = "B", B = "A"}
local result = string.gsub(s, "[AB]", t)
print(result)
or this same one-liner:
print((string.gsub("AABBCC", "[AB]", {A = "B", B = "A"})))
Output:
BBAACC
For a one character pattern like "[AB]", "." can work as well because whatever not found in the table won't be changed. (But I don't think that's more efficient) But for some more complicated cases, a good pattern is needed.
Here is an example from Programming in Lua: this function substitutes the value of the global variable varname for every occurrence of $varname in a string:
function expand (s)
return (string.gsub(s, "$(%w+)", _G))
end
The code below will replace each character with a desired mapping (or leave alone if no mapping exists). You could modify the second parameter to string.gsub in tr to be more specific if you know the exact range of characters.
s = "AABBCC"
mappings = {["A"]="B",["B"]="A"}
function tr(s,mappings)
return string.gsub(s,
"(.)",
function(m)
-- print("found",m,"replace with",mappings[m],mappings[m] or m)
if mappings[m] == nil then return m else return mappings[m] end
end
)
end
print(tr(s,mappings))
Outputs
henry#henry-pc:~/Desktop$ lua replace.lua
found A replace with B B
found A replace with B B
found B replace with A A
found B replace with A A
found C replace with nil C
found C replace with nil C
BBAACC 6

How do I put variable values into a text string in MATLAB?

I'm trying to write a simple function that takes two inputs, x and y, and passes these to three other simple functions that add, multiply, and divide them. The main function should then display the results as a string containing x, y, and the totals.
I think there's something I'm not understanding about output arguments. Anyway, here's my (pitiful) code:
function a=addxy(x,y)
a=x+y;
function b=mxy(x,y)
b=x*y;
function c=dxy(x,y)
c=x/y;
The main function is:
function [d e f]=answer(x,y)
d=addxy(x,y);
e=mxy(x,y);
f=dxy(x,y);
z=[d e f]
How do I get the values for x, y, d, e, and f into a string? I tried different matrices and stuff like:
['the sum of' x 'and' y 'is' d]
but none of the variables are showing up.
Two additional issues:
Why is the function returning "ans 3" even though I didn't ask for the length of z?
If anyone could recommend a good book for beginners to MATLAB scripting I'd really appreciate it.
Here's how you convert numbers to strings, and join strings to other things (it's weird):
>> ['the number is ' num2str(15) '.']
ans =
the number is 15.
You can use fprintf/sprintf with familiar C syntax. Maybe something like:
fprintf('x = %d, y = %d \n x+y=%d \n x*y=%d \n x/y=%f\n', x,y,d,e,f)
reading your comment, this is how you use your functions from the main program:
x = 2;
y = 2;
[d e f] = answer(x,y);
fprintf('%d + %d = %d\n', x,y,d)
fprintf('%d * %d = %d\n', x,y,e)
fprintf('%d / %d = %f\n', x,y,f)
Also for the answer() function, you can assign the output values to a vector instead of three distinct variables:
function result=answer(x,y)
result(1)=addxy(x,y);
result(2)=mxy(x,y);
result(3)=dxy(x,y);
and call it simply as:
out = answer(x,y);
As Peter and Amro illustrate, you have to convert numeric values to formatted strings first in order to display them or concatenate them with other character strings. You can do this using the functions FPRINTF, SPRINTF, NUM2STR, and INT2STR.
With respect to getting ans = 3 as an output, it is probably because you are not assigning the output from answer to a variable. If you want to get all of the output values, you will have to call answer in the following way:
[out1,out2,out3] = answer(1,2);
This will place the value d in out1, the value e in out2, and the value f in out3. When you do the following:
answer(1,2)
MATLAB will automatically assign the first output d (which has the value 3 in this case) to the default workspace variable ans.
With respect to suggesting a good resource for learning MATLAB, you shouldn't underestimate the value of the MATLAB documentation. I've learned most of what I know on my own using it. You can access it online, or within your copy of MATLAB using the functions DOC, HELP, or HELPWIN.
I just realized why I was having so much trouble - in MATLAB you can't store strings of different lengths as an array using square brackets. Using square brackets concatenates strings of varying lengths into a single character array.
>> a=['matlab','is','fun']
a =
matlabisfun
>> size(a)
ans =
1 11
In a character array, each character in a string counts as one element, which explains why the size of a is 1X11.
To store strings of varying lengths as elements of an array, you need to use curly braces to save as a cell array. In cell arrays, each string is treated as a separate element, regardless of length.
>> a={'matlab','is','fun'}
a =
'matlab' 'is' 'fun'
>> size(a)
ans =
1 3
I was looking for something along what you wanted, but wanted to put it back into a variable.
So this is what I did
variable = ['hello this is x' x ', this is now y' y ', finally this is d:' d]
basically
variable = [str1 str2 str3 str4 str5 str6]

Resources