How to get the middle of a string in Python? - python-3.x

Hold on: It's not as easy as it sounds in the title.
I've been working on a very crude AI, and the seemingly hard bits have been easy but this one little function is being really hard.
What I want this to do is get some of the chars that occur before a chars in the string. For example,
get_piece_behind("Hello World", 5, 3) #Return the 3 chars that come before ' ' (the fifth char)
'llo'
get_piece_behind("Hello World", 4, 3) #Return the 3 chars that come before 'o' in "hello" (the fourth char)
'ell'
get_piece_behind("Hello World", 5, 2) #Return the 2 chars that come before the fifth char
'lo'
The code accepts a string, an int marking a place in the string, and an int telling the function how far back it should look.
I get the idea this should be a super-simple one-liner... but my coffee infused brain has been staring at it for the past hour, rewriting it over and over, and nothing seems to work (my current function returns small bits of string, but from the wrong place)
def get_piece_behind(string, place, length_of_piece): #My current function
string = string[(place - length_of_piece):]
string = string[:place]
return string
Does anyone know how to fix this? I get the idea that it's a tiny, stupid error that I will have completely overlooked.
Thanks!

Python strings are sequences, and as such you can use the slice-index syntax to retrieve sub-sequeces of it:
a = "hello world"
a[1:3] # retrieves the chars from the second posistion (index 1) up to the 4th.
# the same, but as you want, putting expressins to calculate the indexes:
a[5-3:5]
a[4-3:4]
I suggest you to read the following document in whole before proceeding with your task - might save you a lot of time:
https://docs.python.org/3/tutorial/introduction.html

You are overlooking in your string splicing.
Try this:
def get_piece_behind(string, place, length_of_piece):
string = string[(place-length_of_piece) : place]
return string

Just do it in one line :) since your string change after first reassignment, also character positions will change:
def get_piece_behind(_string, place, length_of_piece): #My current function
_string = _string[(place - length_of_piece):place]
return _string

The index of characters changes as you cut first with place - length_of_piece, which gives 2, so you were cutting from third char, "llo World" then 5 characters before, resulting in "llo W".
This should work for you:
def get_piece_behind(string, place, length_of_piece):
return string[place-length_of_piece:place]
Output:
llo
ell
lo

Related

String Operations Confusion? ELI5

I'm extremely new to python and I have no idea why this code gives me this output. I tried searching around for an answer but couldn't find anything because I'm not sure what to search for.
An explain-like-I'm-5 explanation would be greatly appreciated
astring = "hello world"
print(astring[3:7:2])
This gives me : "l"
Also
astring = "hello world"
print(astring[3:7:3])
gives me : "lw"
I can't wrap my head around why.
This is string slicing in python.
Slicing is similar to regular string indexing, but it can return a just a section of a string.
Using two parameters in a slice, such as [a:b] will return a string of characters, starting at index a up to, but not including, index b.
For example:
"abcdefg"[2:6] would return "cdef"
Using three parameters performs a similar function, but the slice will only return the character after a chosen gap. For example [2:6:2] will return every second character beginning at index 2, up to index 5.
ie "abcdefg"[2:6:2] will return ce, as it only counts every second character.
In your case, astring[3:7:3], the slice begins at index 3 (the second l) and moves forward the specified 3 characters (the third parameter) to w. It then stops at index 7, returning lw.
In fact when using only two parameters, the third defaults to 1, so astring[2:5] is the same as astring[2:5:1].
Python Central has some more detailed explanations of cutting and slicing strings in python.
I have a feeling you are over complicating this slightly.
Since the string astring is set statically you could more easily do the following:
# Sets the characters for the letters in the consistency of the word
letter-one = "h"
letter-two = "e"
letter-three = "l"
letter-four = "l"
letter-six = "o"
letter-7 = " "
letter-8 = "w"
letter-9 = "o"
letter-10 = "r"
letter11 = "l"
lettertwelve = "d"
# Tells the python which of the character letters that you want to have on the print screen
print(letter-three + letter-7 + letter-three)
This way its much more easily readable to human users and it should mitigate your error.

Cryptopals challenge 4 concern

i am not getting the desired results for Cryptopals challenge 4 set 1.
The concept of the program to check to see if any of these 300ish strings have been XORd by a single character. So with a brute force, my solution is take every string, XOR it with every character on the keyboard, and check to see if any of these results produce an english sentence. if not, then check the next string. Here is my code:
MY_DICT = {}
index = 0
my_plaintext = "Now that the party is jumping"
#fills the dictionary with hex strings from the txt file
with open("hexstrings.txt") as f:
my_list = f.readlines()
for x in my_list:
MY_DICT[index] = x.rstrip('\n')
index = index + 1
i=0
input() #this is just here to help me keep track of where i am when running it
#this loop fills possible_plaintext with all the possible 255 XORs of the i'th string
#of the dictionary that was previously filler from the txt file
for i in range(326):
possible_plaintexts = brute_force_singlechar_xor(MY_DICT[i])
print(possible_plaintexts)
if possible_plaintexts == my_plaintext: #line of concern
print("ya found it yay :) ")
Im sure that myBruteForce function works because it worked properly on the last problem where i XORd every possible char against a string. and i also know that the plaintext is the one provided bc i saw the solution. im just not sure why my program isnt recognizing that the plaintext is not in the dictionary.
(i am aware that using a scoring system to score every string to see if its close to english would be easier, but this is the way i chose to do it for now until i figure out how to get my scoring function to work /: )
How is your dictionary "possible_plaintexts" like when you print it?
Can you spot the solution in the printed text? How is it printed?
The decrypted string should also have a '\n' character.

Remove part of string (regular expressions)

I am a beginner in programming. I have a string for example "test:1" and "test:2". And I want to remove ":1" and ":2" (including :). How can I do it using regular expression?
Hi andrew it's pretty easy. Think of a string as if it is an array of chars (letters) cause it actually IS. If the part of the string you want to delete is allways at the end of the string and allways the same length it goes like this:
var exampleString = 'test:1';
exampleString.length -= 2;
Thats it you just deleted the last two values(letters) of the string(charArray)
If you cant be shure it's allways at the end or the amount of chars to delete you'd to use the version of szymon
There are at least a few ways to do it with Groovy. If you want to stick to regular expression, you can apply expression ^([^:]+) (which means all characters from the beginning of the string until reaching :) to a StringGroovyMethods.find(regexp) method, e.g.
def str = "test:1".find(/^([^:]+)/)
assert str == 'test'
Alternatively you can use good old String.split(String delimiter) method:
def str = "test:1".split(':')[0]
assert str == 'test'

Perl Morgan and a String?

I am trying to solve this problem on hackerrank:
So the problem is:
Jack and Daniel are friends. Both of them like letters, especially upper-case ones.
They are cutting upper-case letters from newspapers, and each one of them has their collection of letters stored in separate stacks.
One beautiful day, Morgan visited Jack and Daniel. He saw their collections. Morgan wondered what is the lexicographically minimal string, made of that two collections. He can take a letter from a collection when it is on the top of the stack.
Also, Morgan wants to use all the letters in the boys' collections.
This is my attempt in Perl:
#!/usr/bin/perl
use strict;
use warnings;
chomp(my $n=<>);
while($n>0){
chomp(my $string1=<>);
chomp(my $string2=<>);
lexi($string1,$string2);
$n--;
}
sub lexi{
my($str1,$str2)=#_;
my #str1=split(//,$str1);
my #str2=split(//,$str2);
my $final_string="";
while(#str2 && #str1){
my $st2=$str2[0];
my $st1=$str1[0];
if($st1 le $st2){
$final_string.=$st1;
shift #str1;
}
else{
$final_string.=$st2;
shift #str2;
}
}
if(#str1){
$final_string=$final_string.join('',#str1);
}
else{
$final_string=$final_string.join('',#str2);
}
print $final_string,"\n";
}
Sample Input:
2
JACK
DANIEL
ABACABA
ABACABA
The first line contains the number of test cases, T.
Every next two lines have such format: the first line contains string A, and the second line contains string B.
Sample Output:
DAJACKNIEL
AABABACABACABA
But for Sample test-case it is giving right results while it is giving wrong results for other test-cases. One case for which it gives an incorrect result is
1
AABAC
AACAB
It outputs AAAABACCAB instead of AAAABACABC.
I don't know what is wrong with the algorithm and why it is failing with other test cases?
Update:
As per #squeamishossifrage comments If I add
($str1,$str2)=sort{$a cmp $b}($str1,$str2);
The results become same irrespective of user-inputs but still the test-case fails.
The problem is in your handling of the equal characters. Take the following example:
ACBA
BCAB
When faced with two identical characters (C in my example), you naïvely chose the one from the first string, but that's not always correct. You need to look ahead to break ties. You may even need to look many characters ahead. In this case, next character after C of the second string is lower than the next character of the first string, so you should take the C from the second string first.
By leaving the strings as strings, a simple string comparison will compare as many characters as needed to determine which character to consume.
sub lexi {
my ($str1, $str2) = #_;
utf8::downgrade($str1); # Makes sure length() will be fast
utf8::downgrade($str2); # since we only have ASCII letters.
my $final_string = "";
while (length($str2) && length($str1)) {
$final_string .= substr($str1 le $str2 ? $str1 : $str2, 0, 1, '');
}
$final_string .= $str1;
$final_string .= $str2;
print $final_string, "\n";
}
Too little rep to comment thus the answer:
What you need to do is to look ahead if the two characters match. You currently do a simple le match and in the case of
ZABB
ZAAA
You'll get ZABBZAA since the first match Z will be le Z. So what you need to do (a naive solution which most likely won't be very effective) is to keep looking as long as the strings/chars match so:
Z eq Z
ZA eq ZA
ZAB gt ZAA
and at that point will you know that the second string is the one you want to pop from for the first character.
Edit
You updated with sorting the strings, but like I wrote you still need to look ahead. The sorting will solve the two above strings but will fail with these two:
ZABAZA
ZAAAZB
ZAAAZBZABAZA
Because here the correct answer is ZAAAZABAZAZB and you can't find that will simply comparing character per character

Convert String of words/letters into an Integer

Today I've finally decided to make an account, in hope for some aid in an issue I've spent the last few hours hunting. (I've spent the past couple hours hunting down a response, from Google to here to Unity Answers. Here's everything that I've found so far, which doesn't work.)
What I'm looking for, is to change a string of purely words/letters into an integer. Therefore "Hello World", would be translated into a string of numbers accordingly. This may be surprising, but this is a lot harder than it sounds. I've found a way to do essentially everything but, thus far.
Presumably the best way would be to get the ASCII value of each letter in the string, and put them all together into a single integer. (No sequences or need to separate them, but one single number.) I have no idea where to get started or how to do that, however. Really anything that you think would work, preferably as short-hand and un-bothersome as possible.
To be as clear as possible, I need to take the letter-only variable "example" and transmorph it to be a integer/only a sequence of numbers.
If you're just trying to convert an arbitrary string into a random seed, then why not try randomSeed.GetHashCode()? That will return an int value suitable for setting the seed, which would produce the same number each time the same string is entered.
You can iterate over all characters, get their charCode and chain them together. The first method splits the string into single chars and uses Array.reduce:
var str = 'qwertzuiop';
var num = parseInt(str.split('').reduce(function(a, b) {return a + b.charCodeAt(0);}, '');
The second calls Array.forEach on the string, because it has numerical indices and a length property.
var num = ''; [].forEach.call(str, function(c) {num += c.charCodeAt(0);});
num = parseInt(num);
In stoneaged browsers you have to use for-loops instead.

Resources