Converting full-width characters to half-width characters - regex

I have a program for converting full width characters to half width. It works fine, except for the number zero. Full-width zero is not converting to half-width zero.
Perl
use strict;
use warnings;
use warnings qw(FATAL utf8);
use utf8;
use feature qw(unicode_strings);
use open qw(:std :utf8);
unless ( #ARGV == 2 ) {
print "Usage: script.pl input_file output_file\n";
exit;
}
my %fwhw = (
'0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4',
'5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9',
'A' => 'A', 'B' => 'B', 'C' => 'C', 'D' => 'D', 'E' => 'E',
'F' => 'F', 'G' => 'G', 'H' => 'H', 'I' => 'I', 'J' => 'J',
'K' => 'K', 'L' => 'L', 'M' => 'M', 'N' => 'N', 'O' => 'O',
'P' => 'P', 'Q' => 'Q', 'R' => 'R', 'S' => 'S', 'T' => 'T',
'U' => 'U', 'V' => 'V', 'W' => 'W', 'X' => 'X', 'Y' => 'Y',
'Z' => 'Z', 'a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd',
'e' => 'e', 'f' => 'f', 'g' => 'g', 'h' => 'h', 'i' => 'i',
'j' => 'j', 'k' => 'k', 'l' => 'l', 'm' => 'm', 'n' => 'n',
'o' => 'o', 'p' => 'p', 'q' => 'q', 'r' => 'r', 's' => 's',
't' => 't', 'u' => 'u', 'v' => 'v', 'w' => 'w', 'x' => 'x',
'y' => 'y', 'z' => 'z', '-' => '-', '、' => ', ', ' ' => ' ',
'/' => '/',);
sub slurp {
my $file = shift;
open my $fh_read, '<', $file or die "Could not open file: $!";
return do {local $/; <$fh_read>};
}
sub convert {
my $sub_string = shift;
$sub_string =~ s/(.)/$fwhw{$1}?$fwhw{$1}:$1/seg;
return $sub_string;
}
my $string = slurp($ARGV[0]);
$string =~ s/<target>\s*<g id="\d+">\K(.*?)(?=<\/g>\s*<\/target>)/convert($1)/seg;
open my $fh_write, ">", $ARGV[1] or die "Could not open file: $!";
print $fh_write $string;
close $fh_write;
Here is what I have tried
I have made sure that the number 0 (zero) and the letter O (oh) are indeed different by checking their code points. Full width 0 is \x{ff10}. Full width letter O is \x{ff2f}. I checked this using this code:
use Encode;
sub codepoint_hex {
sprintf "%04x", ord Encode::decode("UTF-8", shift);
}
my $codepoint = codepoint_hex('0');
print $codepoint, "\n";
I have checked that the hash is indeed loading all of the keys and values correctly.
What I haven't tried yet:
I haven't tried to duplicate this oddity on Linux yet. I am using ActiveState Perl 5.24 on Windows 10.
If anyone has any suggestions or sees my mistake, I would be very grateful for the guidance.

Since $fwhw{'0'} returns 0, and since 0 is false, the replacement doesn't occur. Replace
$sub_string =~ s/(.)/$fwhw{$1}?$fwhw{$1}:$1/seg;
with
$sub_string =~ s/(.)/exists($fwhw{$1})?$fwhw{$1}:$1/seg;
If that still doesn't work, use sprintf "%vX", $str to see what you really have.
By the way,
sub convert {
my $sub_string = shift;
$sub_string =~ s/(.)/exists($fwhw{$1})?$fwhw{$1}:$1/seg;
return $sub_string;
}
would be much faster if replaced with
sub convert {
state $chars = join '', keys(%fwhw);
state $re = qr/([\Q$chars\E])/;
return $_[0] =~ s/$re/$fwhw{$1}/gr;
}
Faster yet,
sub convert {
state $s = join '', keys(%fwhw);
state $r = join '', values(%fwhw);
state $tr = eval("sub { $_[0] =~ tr/\Q$s\E/\Q$r\E/r }");
return $tr->($_[0]);
}

You don't need such a huge dictionary with lots of supporting functions like that. Just a simple sed is enough
halfwidth='!"#$%&'\''()*+,-.\/0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆¢£¬¯¦¥₩ '
fullwidth='!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆¢£¬ ̄¦¥₩ '
sed -ie "y/$fullwidth/$halfwidth/" your_file
If you want to do that in perl it's pretty simple too
perl -Mutf8 -i -C -pe 'BEGIN{ use open qw/:std :utf8/; } tr#!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆¢£¬ ̄¦¥₩ #!"\#$%&'\''()*+,-.\/0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⦅⦆¢£¬¯¦¥₩ # your_file'

Related

Why does `=~` behave differently than `eq` and `==` in list context?

Consider
my #array = ( 'x' =~ /y/, 'x' eq 'y', 1 == 2 );
and
my %hash = ( 'a', 'x' =~ /y/, 'b', 'x' eq 'y', 'c', 1 == 2 );
Using Data::Dumper, we see that =~ behaves differently than eq and ==
\#array = [
'',
''
];
\%hash = {
'a' => 'b',
'' => undef
};
Specifically it appears that the snippets of code above are being interpreted as
my #array = ( 'x' eq 'y', 1 == 2 );
and
my %hash = ( 'a', 'b', 'x' eq 'y', 'c', 1 == 2 );
Can someone provide an explanation for this arguably unexpected behavior?
The match operation you use is not only about finding out if something has matched (scalar context) but also to give the match results (list context). To cite from the documentation:
Matching in list context
m// in list context returns a list consisting of the subexpressions matched by the parentheses in the pattern, that is, ($1, $2, $3...) (Note that here $1 etc. are also set). When there are no parentheses in the pattern, the return value is the list (1) for success. With or without parentheses, an empty list is returned upon failure

Why do #+ and #{^CAPTURE} differ in length?

I'm trying to understand how the regex variables work, so I can save submatch positions in the payload within embedded code expressions. According to perlvar, the positive indices of the array correspond to $1, $2, $3, etc., but that doesn't seem to be the case?
#!/usr/bin/perl -w
use v5.28;
use Data::Dumper;
"XY" =~ / ( (.*) (.) (?{
say Dumper { match_end => \#+ };
say Dumper { capture => \#{^CAPTURE} }
}) ) (.)/x;
Output:
$VAR1 = {
'match_end' => [
2,
undef,
1,
2,
undef
]
};
$VAR1 = {
'capture' => [
undef,
'X',
'Y'
]
};
$VAR1 = {
'match_end' => [
1,
2,
0,
1,
undef
]
};
$VAR1 = {
'capture' => [
'XY',
'',
'X'
]
};
The #+ array apparently gets allocated, or otherwise prepared, already at compilation
perl -MData::Dump=dd -we'$_=q(abc); / (?{dd #+}) ( (.) )/x'
prints
(0, undef, undef)
(0 for the whole match and an undef for each indicated capture group), while
perl -MData::Dump=dd -we'$_=q(abc); / (?{dd #+}) ( (.) (.) )/x'
prints
(0, undef, undef, undef)
with one more element for one more capture group.
One the other hand, the #{^CAPTURE} is just plain empty until there are actual patterns to capture, as we can see from mob's detailed analysis. This, I'd say, plays well with its name.
After the fact the arrays agree, with that shift of one in indices since #+ also contains (offset for) the whole match, at $+[0].
Another difference is that a trailing failed optional match doesn't get a slot in #{^CAPTURE}
perl -MData::Dump=dd -we'$_=q(abc); /((x)? (.) (x)?)/x; dd #+; dd #{^CAPTURE}'
prints
(1, 1, undef, 1, undef)
("a", undef, "a")
The perlvar docs are unclear about what #{^CAPTURE} look like in the middle of a regexp evaluation, but there is a clear progression that depends where in the regexp you are looking at it.
use 5.026;
use Data::Dumper; $Data::Dumper::Sortkeys = 1; $Data::Dumper::Indent = 0;
sub DEBUG_CAPTURE { say Dumper { a => $_[0], capture => \#{^CAPTURE} }; }
"XY" =~ /
(?{DEBUG_CAPTURE(0)})
(
(?{DEBUG_CAPTURE(1)})
(
(?{DEBUG_CAPTURE(2)})
(.*) (?{DEBUG_CAPTURE(3)})
(.) (?{DEBUG_CAPTURE(4)})
)
(?{DEBUG_CAPTURE(5)}) (.)
(?{DEBUG_CAPTURE(6)})
)
(?{DEBUG_CAPTURE(7)}) /x;
DEBUG_CAPTURE(8);
Output
$VAR1 = {'a' => 0,'capture' => []};
$VAR1 = {'a' => 1,'capture' => []};
$VAR1 = {'a' => 2,'capture' => []};
$VAR1 = {'a' => 3,'capture' => [undef,undef,'XY']};
$VAR1 = {'a' => 3,'capture' => [undef,undef,'X']};
$VAR1 = {'a' => 4,'capture' => [undef,undef,'X','Y']};
$VAR1 = {'a' => 5,'capture' => [undef,'XY','X','Y']};
$VAR1 = {'a' => 3,'capture' => [undef,'XY','','Y']};
$VAR1 = {'a' => 4,'capture' => [undef,'XY','','X']};
$VAR1 = {'a' => 5,'capture' => [undef,'X','','X']};
$VAR1 = {'a' => 6,'capture' => [undef,'X','','X','Y']};
$VAR1 = {'a' => 7,'capture' => ['XY','X','','X','Y']};
$VAR1 = {'a' => 8,'capture' => ['XY','X','','X','Y']};
The docs are correct if you are observing #{^CAPTURE} after a regexp has been completely evaluated. While evaluation is in process, #{^CAPTURE} seems to grow as the number of capture groups encountered increases. But it's not clear how useful it is to look at #{^CAPTURE} at least until you get to the end of the expression.

Script for importing categories to opencart won't work

I have scripts for importing categories and products from XML to Opencart.
This script was written for Opencart 2.1.0.2 and now I want to use this script for version 1.5.6.1.
After run this script It wrote me error - "Failed loading XML:"
And thats all.
Is something different in code for older version of Opencart?
Thanks.
Here is example of script for importing categories:
<?php
// Version
define('VERSION', '1.5.6.1');
// Configuration
if (is_file('config.php')) {
require_once('config.php');
}
// Install
if (!defined('DIR_APPLICATION')) {
header('Location: install/index.php');
exit;
}
// Startup
require_once(DIR_SYSTEM . 'startup.php');
// Registry
$registry = new Registry();
// Loader
$loader = new Loader($registry);
$registry->set('load', $loader);
// Config
$config = new Config();
$registry->set('config', $config);
// Database
$db = new DB(DB_DRIVER, DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE, DB_PORT);
$registry->set('db', $db);
ob_start();
echo "<pre>";
// initialize xml
$xmlfiles = glob('./import/categories.xml');
if (count($xmlfiles) > 0) {
$xmlfiletmp = $xmlfiles[0];
$fileNameParts = explode('/', $xmlfiletmp);
$xmlfile = end($fileNameParts);
} else {
die('xml doesnt exist');
}
$xmlFileContent = file_get_contents('./import/categories.xml' . $xmlfile);
// $xmlFileContent = file_get_contents('./import/categories.xml');
$xml = simplexml_load_string($xmlFileContent);
if ($xml === false) {
echo "Failed loading XML: ";
foreach(libxml_get_errors() as $error) {
echo "<br>", $error->message;
}
die();
} else {
echo "XML loaded<br>";
}
$language_id = 4;
$store_id = 0;
$layout_id = 0;
$oldCategories = [];
$newCategories = [];
// load old categories
$query = $db->query("SELECT * FROM `" . DB_PREFIX . "category`");
foreach ($query->rows as $result) {
$oldCategories[$result['menu_id_abra']] = $result;
}
// print_r($oldCategories['9000000101']);
// die('s');
echo "###### START<br>";
// loop new categories
foreach ($xml as $category) {
// $newCategories[$category['Menu_id_abra']] = $category;
// $oldCategories[$category['Menu_id_abra']] = $category;
$cId = (string)$category['Menu_id_abra'];
$parentIdAbraCasted = (string)$category['Parent_id_abra'];
// parent exists?
$parentId = 0;
if (isset($oldCategories[$parentIdAbraCasted])) {
$parentId = $oldCategories[$parentIdAbraCasted]['category_id'];
}
$status = (string)$category['aktivne'] == 'Áno' ? 0 : 1;
if (isset($oldCategories[$cId])) {
// update
echo "Updating ... ";
$category_id = $oldCategories[$cId]['category_id'];
$db->query("UPDATE " . DB_PREFIX . "category SET parent_id = '" . (int)$parentId . "', `top` = '1', `column` = '1', status = '" . $status . "', date_modified = NOW(), menu_id_abra = '" . $category['Menu_id_abra'] . "', parent_id_abra = '" . $category['Parent_id_abra'] . "', pos_index_abra = '" . $category['PosIndex'] . "', sort_order = '" . $category['PosIndex'] . "' WHERE category_id = '" . (int)$category_id . "'");
$db->query("UPDATE " . DB_PREFIX . "category_description SET name = '" . $db->escape($category['Nazov_menu']) . "', meta_title = '" . $db->escape($category['Nazov_menu']) . "' WHERE category_id = '" . (int)$category_id . "' AND language_id = '" . (int)$language_id . "'");
$db->query("DELETE FROM " . DB_PREFIX . "url_alias WHERE query = 'category_id=" . (int)$category_id . "'");
$db->query("INSERT INTO " . DB_PREFIX . "url_alias SET query = 'category_id=" . (int)$category_id . "', keyword = '" . $db->escape(toURI($category['Nazov_menu'])) . "'");
$db->query("UPDATE " . DB_PREFIX . "category_to_layout SET store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "' WHERE category_id = '" . (int)$category_id . "'");
// MySQL Hierarchical Data Closure Table Pattern
$db->query("DELETE FROM " . DB_PREFIX . "category_path WHERE category_id = '" . (int)$category_id . "'");
$level = 0;
$query = $db->query("SELECT * FROM `" . DB_PREFIX . "category_path` WHERE category_id = '" . (int)$parentId . "' ORDER BY `level` ASC");
foreach ($query->rows as $result) {
$db->query("INSERT INTO `" . DB_PREFIX . "category_path` SET `category_id` = '" . (int)$category_id . "', `path_id` = '" . (int)$result['path_id'] . "', `level` = '" . (int)$level . "'");
$level++;
}
$db->query("INSERT INTO `" . DB_PREFIX . "category_path` SET `category_id` = '" . (int)$category_id . "', `path_id` = '" . (int)$category_id . "', `level` = '" . (int)$level . "'");
echo 'updated with ID ' . $category_id;
} else {
// create
echo "Creating ... ";
$db->query("INSERT INTO " . DB_PREFIX . "category SET parent_id = '" . (int)$parentId . "', `top` = '0', `column` = '1', status = '" . $status . "', date_modified = NOW(), date_added = NOW(), menu_id_abra = '" . $category['Menu_id_abra'] . "', parent_id_abra = '" . $category['Parent_id_abra'] . "', pos_index_abra = '" . $category['PosIndex'] . "', sort_order = '" . $category['PosIndex'] . "'");
$category_id = $db->getLastId();
$db->query("INSERT INTO " . DB_PREFIX . "category_description SET category_id = '" . (int)$category_id . "', language_id = '" . (int)$language_id . "', name = '" . $db->escape($category['Nazov_menu']) . "', description = '" . $db->escape($category['Nazov_menu']) . "', meta_title = '" . $db->escape($category['Nazov_menu']) . "'");
$db->query("INSERT INTO " . DB_PREFIX . "category_to_store SET category_id = '" . (int)$category_id . "', store_id = '" . (int)$store_id . "'");
$db->query("INSERT INTO " . DB_PREFIX . "category_to_layout SET category_id = '" . (int)$category_id . "', store_id = '" . (int)$store_id . "', layout_id = '" . (int)$layout_id . "'");
$db->query("INSERT INTO " . DB_PREFIX . "url_alias SET query = 'category_id=" . (int)$category_id . "', keyword = '" . $db->escape(toURI($category['Nazov_menu'])) . "'");
// MySQL Hierarchical Data Closure Table Pattern
$level = 0;
$query = $db->query("SELECT * FROM `" . DB_PREFIX . "category_path` WHERE category_id = '" . (int)$parentId . "' ORDER BY `level` ASC");
foreach ($query->rows as $result) {
$db->query("INSERT INTO `" . DB_PREFIX . "category_path` SET `category_id` = '" . (int)$category_id . "', `path_id` = '" . (int)$result['path_id'] . "', `level` = '" . (int)$level . "'");
$level++;
}
$db->query("INSERT INTO `" . DB_PREFIX . "category_path` SET `category_id` = '" . (int)$category_id . "', `path_id` = '" . (int)$category_id . "', `level` = '" . (int)$level . "'");
// $newCategories[$category['Menu_id_abra']]['category_id'] = $category_id;
$oldCategories[$cId] = ['category_id'=>$category_id];
echo 'created with ID ' . $category_id;
}
echo '<br>';
}
// print_r($oldCategories);
rename ("./import/" . $xmlfile, "./import/IMPORTED/" . $xmlfile);
$htmlStr = ob_get_contents();
// Clean (erase) the output buffer and turn off output buffering
ob_end_clean();
file_put_contents('./importlogs/categoriesimport_' . time() , $htmlStr);
echo $htmlStr;
function replace_accent($str)
{
$a = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', 'Ā', 'ā', 'Ă', 'ă', 'Ą', 'ą', 'Ć', 'ć', 'Ĉ', 'ĉ', 'Ċ', 'ċ', 'Č', 'č', 'Ď', 'ď', 'Đ', 'đ', 'Ē', 'ē', 'Ĕ', 'ĕ', 'Ė', 'ė', 'Ę', 'ę', 'Ě', 'ě', 'Ĝ', 'ĝ', 'Ğ', 'ğ', 'Ġ', 'ġ', 'Ģ', 'ģ', 'Ĥ', 'ĥ', 'Ħ', 'ħ', 'Ĩ', 'ĩ', 'Ī', 'ī', 'Ĭ', 'ĭ', 'Į', 'į', 'İ', 'ı', 'IJ', 'ij', 'Ĵ', 'ĵ', 'Ķ', 'ķ', 'Ĺ', 'ĺ', 'Ļ', 'ļ', 'Ľ', 'ľ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'Ń', 'ń', 'Ņ', 'ņ', 'Ň', 'ň', 'ʼn', 'Ō', 'ō', 'Ŏ', 'ŏ', 'Ő', 'ő', 'Œ', 'œ', 'Ŕ', 'ŕ', 'Ŗ', 'ŗ', 'Ř', 'ř', 'Ś', 'ś', 'Ŝ', 'ŝ', 'Ş', 'ş', 'Š', 'š', 'Ţ', 'ţ', 'Ť', 'ť', 'Ŧ', 'ŧ', 'Ũ', 'ũ', 'Ū', 'ū', 'Ŭ', 'ŭ', 'Ů', 'ů', 'Ű', 'ű', 'Ų', 'ų', 'Ŵ', 'ŵ', 'Ŷ', 'ŷ', 'Ÿ', 'Ź', 'ź', 'Ż', 'ż', 'Ž', 'ž', 'ſ', 'ƒ', 'Ơ', 'ơ', 'Ư', 'ư', 'Ǎ', 'ǎ', 'Ǐ', 'ǐ', 'Ǒ', 'ǒ', 'Ǔ', 'ǔ', 'Ǖ', 'ǖ', 'Ǘ', 'ǘ', 'Ǚ', 'ǚ', 'Ǜ', 'ǜ', 'Ǻ', 'ǻ', 'Ǽ', 'ǽ', 'Ǿ', 'ǿ');
$b = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o');
return str_replace($a, $b, $str);
}
function toURI($str, $replace = array(), $delimiter = '-')
{
if(!empty($replace))
{
$str = str_replace((array) $replace, ' ', $str);
}
$clean=replace_accent($str);
$clean = iconv('UTF-8', 'ASCII//TRANSLIT', $clean);
$clean = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
$clean = strtolower(trim($clean, '-'));
$clean = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);
return $clean;
}

While loop inside While loop in python?

I am a beginner in python.
The second loop only run for once, the first time only, but when the turn comes to the first loop and when e = e+1 - python skips the second loop!
Why?
The print order only work for once.
items = [['.', '.', '.', '.', '.', '.'],
['.', 'O', 'O', '.', '.', '.'],
['O', 'O', 'O', 'O', '.', '.'],
['O', 'O', 'O', 'O', 'O', '.'],
['.', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', '.'],
['O', 'O', 'O', 'O', '.', '.'],
['.', 'O', 'O', '.', '.', '.'],
['.', '.', '.', '.', '.', '.']]
i=0
e=0
while e < 6 :
while i < 9 : #python run this loop only once, and never come back when e=e+1
print items[i][e]
i=i+1
e=e+1
After the 'i' loop runs once, i will be set to 9 and will stay as 9 until you reset.
so you can try to set it to 0 after e = e+1.
A useful technique you can try is also printing the values of 'e' and 'i' to see where the loops gone wrong
items = [['.', '.', '.', '.', '.', '.'],
['.', 'O', 'O', '.', '.', '.'],
['O', 'O', 'O', 'O', '.', '.'],
['O', 'O', 'O', 'O', 'O', '.'],
['.', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', '.'],
['O', 'O', 'O', 'O', '.', '.'],
['.', 'O', 'O', '.', '.', '.'],
['.', '.', '.', '.', '.', '.']]
i=0
e=0
while e <6 :
while i <9 :
print items[i][e]
print 'loop: i'+str(i)+'e'+str(e)
i=i+1
e=e+1
i=0

Find if certain characters are present in a string

I have the following code and want to see if the string 'userFirstName' contains any of the characters in the char array. If the string does I want it to ask the user to reenter their first name and then check the new name for invalid characters and so on.
char invalidCharacter[] = { '!', '#', '#', '$', '%', '^', '&', '*', '(', ')', '~', '`',
';', ':', '+', '=', '-', '_', '*', '/', '.', '<', '>', '?', ',', '[', ']', '{', '}',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
cout << "Please enter your first name: " << endl;
cin >> userFirstName;`
Use string::find_first_of to do it.
Assuming that userFirstName is a string:
size_t pos = userFirstName.find_first_of(invalidChars, 0, sizeof(invalidChars));
if (pos != string::npos) {
// username contains an invalid character at index pos
}